11c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten/*
21c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
31c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten *
41c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
51c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * you may not use this file except in compliance with the License.
61c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * You may obtain a copy of the License at
71c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten *
81c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
91c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten *
101c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * Unless required by applicable law or agreed to in writing, software
111c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
121c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * See the License for the specific language governing permissions and
141c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten * limitations under the License.
151c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten */
161c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
171c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten// multiplay is a command-line test app that plays multiple files randomly
181c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
19c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h>
201c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten#include <assert.h>
211c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten#include <string.h>
221c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten#include <stdlib.h>
231c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten#include <stdio.h>
24c2303eb5497c488db786dcb2b8514db229452536Glenn Kasten#include <unistd.h>
251c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
261c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten// Describes the state of one player
271c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
281c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kastentypedef struct {
291c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLObjectItf mPlayerObject;
301c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLPlayItf mPlayerPlay;
311c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLSeekItf mPlayerSeek;
32d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    SLPrefetchStatusItf mPlayerPrefetchStatus;
331c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLVolumeItf mPlayerVolume;
341c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLmillisecond mPlayerDuration;
35d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    SLboolean mPlayerErrorInCallback;
36d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    SLboolean mPlayerErrorReported;
371c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten} Player;
381c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
391c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten// Strings corresponding to result codes; FIXME should move to a common test library
401c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
411c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kastenstatic const char *result_strings[] = {
421c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "SUCCESS",
431c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "PRECONDITIONS_VIOLATED",
441c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "PARAMETER_INVALID",
451c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "MEMORY_FAILURE",
461c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "RESOURCE_ERROR",
471c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "RESOURCE_LOST",
481c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "IO_ERROR",
491c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "BUFFER_INSUFFICIENT",
501c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "CONTENT_CORRUPTED",
511c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "CONTENT_UNSUPPORTED",
521c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "CONTENT_NOT_FOUND",
531c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "PERMISSION_DENIED",
541c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "FEATURE_UNSUPPORTED",
551c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "INTERNAL_ERROR",
561c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "UNKNOWN_ERROR",
571c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "OPERATION_ABORTED",
581c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    "CONTROL_LOST"
591c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten};
601c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
611c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten// Convert result to string; FIXME should move to common test library
621c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
631c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kastenstatic const char *result_to_string(SLresult result)
641c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten{
651c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    static char buffer[32];
661c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    if ( /* result >= 0 && */ result < sizeof(result_strings) / sizeof(result_strings[0]))
671c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        return result_strings[result];
684b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    sprintf(buffer, "%d", (int) result);
691c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    return buffer;
701c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten}
711c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
721c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten// Compare result against expected and exit suddenly if wrong
731c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
741c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kastenvoid check2(SLresult result, int line)
751c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten{
761c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    if (SL_RESULT_SUCCESS != result) {
771c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        fprintf(stderr, "error %s at line %d\n", result_to_string(result), line);
781c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        exit(EXIT_FAILURE);
791c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    }
801c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten}
811c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
821c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten// Same as above but automatically adds the source code line number
831c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
841c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten#define check(result) check2(result, __LINE__)
851c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
86d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten// Prefetch status callback
87d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten
88d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten#define PREFETCHEVENT_ERROR_CANDIDATE \
89d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten            (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
90d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten
91d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kastenvoid prefetch_callback(SLPrefetchStatusItf caller, void *context, SLuint32 event)
92d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten{
93d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    SLresult result;
94d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    assert(context != NULL);
95d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    Player *p = (Player *) context;
96d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    assert(p->mPlayerPrefetchStatus == caller);
97d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    SLpermille level;
98d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    result = (*caller)->GetFillLevel(caller, &level);
99d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    check(result);
100d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    SLuint32 status;
101d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    result = (*caller)->GetPrefetchStatus(caller, &status);
102d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    check(result);
103d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    //fprintf(stderr, "PrefetchEventCallback: received event %u, level %u, status %u\n",
104d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    //      event, level, status);
105d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
106d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten            && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
107d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        p->mPlayerErrorInCallback = SL_BOOLEAN_TRUE;
108d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    }
109d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten}
110d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten
1111c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten// Main program
1121c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
1131c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kastenint main(int argc, char **argv)
1141c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten{
1151c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    int i;
1161c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    const char *arg;
1171c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    int numPlayers = 0;
1180a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    int playTimeInMilliseconds = 0; // default to run forever
1191c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLmillibel mixVolumeLevel = 0;
1201c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    for (i = 1; i < argc; ++i) {
1211c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        arg = argv[i];
1221c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        if (arg[0] != '-')
1231c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            break;
1241c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        if (!strncmp(arg, "-n", 2))
1251c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            numPlayers = atoi(&arg[2]);
1261c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        else if (!strncmp(arg, "-v", 2))
1271c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            mixVolumeLevel = atoi(&arg[2]);
1280a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        else if (!strncmp(arg, "-t", 2))
1290a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            playTimeInMilliseconds = atoi(&arg[2]) * 1000;
1301c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        else
1311c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            fprintf(stderr, "unknown option: %s\n", arg);
1321c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    }
1331c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    int numPathnames = argc - i;
1341c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    if (numPathnames <= 0) {
1351c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        fprintf(stderr, "usage: %s file.wav ...\n", argv[0]);
1361c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        return EXIT_FAILURE;
1371c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    }
138d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    if (numPlayers <= 0) {
1391c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        numPlayers = numPathnames;
140d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    }
141d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten    Player *players = (Player *) calloc(numPlayers, sizeof(Player));
1421c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    assert(NULL != players);
1431c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    char **pathnames = &argv[i];
1441c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLresult result;
1451c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
1461c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    // engine
1471c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    const SLInterfaceID engine_ids[] = {SL_IID_ENGINE};
1481c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    const SLboolean engine_req[] = {SL_BOOLEAN_TRUE};
1491c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLObjectItf engineObject;
1501c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 1, engine_ids, engine_req);
1511c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    check(result);
1521c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
1531c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    check(result);
1541c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLEngineItf engineEngine;
1551c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
1561c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    check(result);
1571c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
1581c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    // mixer
1591c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    const SLInterfaceID mix_ids[] = {SL_IID_VOLUME};
1601c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    const SLboolean mix_req[] = {SL_BOOLEAN_TRUE};
1611c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLObjectItf mixObject;
162c2303eb5497c488db786dcb2b8514db229452536Glenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, 0, mix_ids, mix_req);
1631c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    check(result);
1641c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
1651c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    check(result);
166c2303eb5497c488db786dcb2b8514db229452536Glenn Kasten#if 0
1671c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLVolumeItf mixVolume;
1681c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    result = (*mixObject)->GetInterface(mixObject, SL_IID_VOLUME, &mixVolume);
1691c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    check(result);
1701c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    SLmillibel mixVolumeLevelDefault;
1711c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    result = (*mixVolume)->GetVolumeLevel(mixVolume, &mixVolumeLevelDefault);
1721c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    check(result);
1731c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    printf("default mix volume level = %d\n", mixVolumeLevelDefault);
174c2303eb5497c488db786dcb2b8514db229452536Glenn Kasten#endif
1751c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
1761c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    printf("numPathnames=%d\n", numPathnames);
1771c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    printf("numPlayers=%d\n", numPlayers);
1781c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    Player *p;
1791c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
1801c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    // create all the players
1811c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    for (i = 0; i < numPlayers; ++i) {
182d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        const SLInterfaceID player_ids[] =
183d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten                {SL_IID_PLAY, SL_IID_VOLUME, SL_IID_SEEK, SL_IID_PREFETCHSTATUS};
184d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        const SLboolean player_req[] =
185d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten                {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
1861c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        p = &players[i];
1871c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, (SLchar *) pathnames[i % numPathnames]};
1881c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
1891c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        SLDataSource audioSrc = {&locURI, &dfMIME};
1901c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject};
1911c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        SLDataSink audioSnk = {&locOutputMix, NULL};
192ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = (*engineEngine)->CreateAudioPlayer(engineEngine, &p->mPlayerObject, &audioSrc,
193d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten            &audioSnk, sizeof(player_ids)/sizeof(player_ids[0]), player_ids, player_req);
1941c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        check(result);
1951c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        result = (*p->mPlayerObject)->Realize(p->mPlayerObject, SL_BOOLEAN_FALSE);
1961c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        check(result);
1971c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_PLAY, &p->mPlayerPlay);
1981c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        check(result);
199ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_VOLUME,
200ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            &p->mPlayerVolume);
2011c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        check(result);
2021c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_SEEK, &p->mPlayerSeek);
2031c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        check(result);
204d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_PREFETCHSTATUS,
205d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten                &p->mPlayerPrefetchStatus);
206d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        check(result);
207d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        result = (*p->mPlayerPrefetchStatus)->RegisterCallback(p->mPlayerPrefetchStatus,
208d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten                prefetch_callback, p);
209d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        check(result);
210d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        result = (*p->mPlayerPrefetchStatus)->SetCallbackEventsMask(p->mPlayerPrefetchStatus,
211d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten                SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE);
2121c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        check(result);
2131c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    }
2141c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
2151c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    // now loop randomly doing things to the players
2161c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    for (;;) {
2171c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        SLmillisecond delay = 100 + (rand() & 1023);
2184b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        printf("sleep %u\n", (unsigned) delay);
2191c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        usleep(delay * 1000);
2201c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        i = (rand() & 0x7FFFFFFF) % numPlayers;
2211c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        p = &players[i];
222d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        if (p->mPlayerErrorReported)
223d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten            continue;
224d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        printf("player %d (%s): ", i, pathnames[i]);
225d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        if (p->mPlayerErrorInCallback && !p->mPlayerErrorReported) {
226d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten            printf("error, ");
227d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten            p->mPlayerErrorReported = SL_BOOLEAN_TRUE;
228d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        }
229d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        result = (*p->mPlayerPlay)->GetDuration(p->mPlayerPlay, &p->mPlayerDuration);
230d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        check(result);
231d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        if (p->mPlayerDuration == SL_TIME_UNKNOWN) {
232d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten            printf("duration unknown, ");
233d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        } else {
234d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten            printf("duration %d ms, ", (int) p->mPlayerDuration);
235d91db4c34bdffa3b6d3f9234c8f4f8506bc0aa2eGlenn Kasten        }
2361c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        SLuint32 state;
2371c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        result = (*p->mPlayerPlay)->GetPlayState(p->mPlayerPlay, &state);
2381c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        check(result);
2391c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        printf("state = ");
2401c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        switch (state) {
2411c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        case SL_PLAYSTATE_STOPPED:
2421c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            printf("STOPPED");
2431c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            break;
2441c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        case SL_PLAYSTATE_PAUSED:
2451c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            printf("PAUSED");
2461c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            break;
2471c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        case SL_PLAYSTATE_PLAYING:
2481c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            printf("PLAYING");
2491c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            break;
2501c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        default:
2514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            printf("%u", (unsigned) state);
2521c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            break;
2531c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        }
2544b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        printf("\n");
2551c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        if (state == SL_PLAYSTATE_STOPPED || state == SL_PLAYSTATE_PAUSED) {
2561c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            SLmillibel volumeLevel = -((rand() & 0x7FFFFFFF) % ((SL_MILLIBEL_MIN + 1) / 10));
2574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            printf("volume %d\n", volumeLevel);
2581c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            result = (*p->mPlayerVolume)->SetVolumeLevel(p->mPlayerVolume, volumeLevel);
2591c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            check(result);
2601c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            result = (*p->mPlayerVolume)->EnableStereoPosition(p->mPlayerVolume, SL_BOOLEAN_TRUE);
2611c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            check(result);
2621c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            SLpermille stereoPosition = ((rand() & 0x7FFFFFFF) % 2001) - 1000;
2634b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            printf("position %d\n", stereoPosition);
2641c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            result = (*p->mPlayerVolume)->SetStereoPosition(p->mPlayerVolume, stereoPosition);
2651c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            check(result);
2661c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            if (state != SL_PLAYSTATE_STOPPED) {
2671c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten                result = (*p->mPlayerSeek)->SetPosition(p->mPlayerSeek, 0, SL_SEEKMODE_FAST);
2681c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten                check(result);
2691c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            }
2701c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            result = (*p->mPlayerPlay)->SetPlayState(p->mPlayerPlay, SL_PLAYSTATE_PLAYING);
2711c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten            check(result);
2721c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten        }
2730a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        if ((playTimeInMilliseconds > 0) && ((playTimeInMilliseconds -= delay) < 0))
2740a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten            break;
2751c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten    }
2761c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
2770a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    for (i = 0; i < numPlayers; ++i) {
2780a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        SLObjectItf playerObject = players[i].mPlayerObject;
2790a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten        (*playerObject)->Destroy(playerObject);
2800a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    }
2810a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*mixObject)->Destroy(mixObject);
2820a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    (*engineObject)->Destroy(engineObject);
2831c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten
2840a058cc3d720cdf3f0f8222472a862258482f34fGlenn Kasten    return EXIT_SUCCESS;
2851c1c16f5469b9ebb4943e2c5eb648f832e0a3c37Glenn Kasten}
286