multiplay.c revision c6853892c94800e72c0bd676d5d2136d48cea76e
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// multiplay is a command-line test app that plays multiple files randomly
18
19#include <SLES/OpenSLES.h>
20#include <assert.h>
21#include <string.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <unistd.h>
25
26// Describes the state of one player
27
28typedef struct {
29    SLObjectItf mPlayerObject;
30    SLPlayItf mPlayerPlay;
31    SLSeekItf mPlayerSeek;
32    SLVolumeItf mPlayerVolume;
33    SLmillisecond mPlayerDuration;
34} Player;
35
36// Strings corresponding to result codes; FIXME should move to a common test library
37
38static const char *result_strings[] = {
39    "SUCCESS",
40    "PRECONDITIONS_VIOLATED",
41    "PARAMETER_INVALID",
42    "MEMORY_FAILURE",
43    "RESOURCE_ERROR",
44    "RESOURCE_LOST",
45    "IO_ERROR",
46    "BUFFER_INSUFFICIENT",
47    "CONTENT_CORRUPTED",
48    "CONTENT_UNSUPPORTED",
49    "CONTENT_NOT_FOUND",
50    "PERMISSION_DENIED",
51    "FEATURE_UNSUPPORTED",
52    "INTERNAL_ERROR",
53    "UNKNOWN_ERROR",
54    "OPERATION_ABORTED",
55    "CONTROL_LOST"
56};
57
58// Convert result to string; FIXME should move to common test library
59
60static const char *result_to_string(SLresult result)
61{
62    static char buffer[32];
63    if ( /* result >= 0 && */ result < sizeof(result_strings) / sizeof(result_strings[0]))
64        return result_strings[result];
65    sprintf(buffer, "%d", (int) result);
66    return buffer;
67}
68
69// Compare result against expected and exit suddenly if wrong
70
71void check2(SLresult result, int line)
72{
73    if (SL_RESULT_SUCCESS != result) {
74        fprintf(stderr, "error %s at line %d\n", result_to_string(result), line);
75        exit(EXIT_FAILURE);
76    }
77}
78
79// Same as above but automatically adds the source code line number
80
81#define check(result) check2(result, __LINE__)
82
83// Main program
84
85int main(int argc, char **argv)
86{
87    int i;
88    const char *arg;
89    int numPlayers = 0;
90    int playTimeInMilliseconds = 0; // default to run forever
91    SLmillibel mixVolumeLevel = 0;
92    for (i = 1; i < argc; ++i) {
93        arg = argv[i];
94        if (arg[0] != '-')
95            break;
96        if (!strncmp(arg, "-n", 2))
97            numPlayers = atoi(&arg[2]);
98        else if (!strncmp(arg, "-v", 2))
99            mixVolumeLevel = atoi(&arg[2]);
100        else if (!strncmp(arg, "-t", 2))
101            playTimeInMilliseconds = atoi(&arg[2]) * 1000;
102        else
103            fprintf(stderr, "unknown option: %s\n", arg);
104    }
105    int numPathnames = argc - i;
106    if (numPathnames <= 0) {
107        fprintf(stderr, "usage: %s file.wav ...\n", argv[0]);
108        return EXIT_FAILURE;
109    }
110    if (numPlayers <= 0)
111        numPlayers = numPathnames;
112    Player *players = (Player *) malloc(sizeof(Player) * numPlayers);
113    assert(NULL != players);
114    char **pathnames = &argv[i];
115    SLresult result;
116
117    // engine
118    const SLInterfaceID engine_ids[] = {SL_IID_ENGINE};
119    const SLboolean engine_req[] = {SL_BOOLEAN_TRUE};
120    SLObjectItf engineObject;
121    result = slCreateEngine(&engineObject, 0, NULL, 1, engine_ids, engine_req);
122    check(result);
123    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
124    check(result);
125    SLEngineItf engineEngine;
126    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
127    check(result);
128
129    // mixer
130    const SLInterfaceID mix_ids[] = {SL_IID_VOLUME};
131    const SLboolean mix_req[] = {SL_BOOLEAN_TRUE};
132    SLObjectItf mixObject;
133    result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, 0, mix_ids, mix_req);
134    check(result);
135    result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
136    check(result);
137#if 0
138    SLVolumeItf mixVolume;
139    result = (*mixObject)->GetInterface(mixObject, SL_IID_VOLUME, &mixVolume);
140    check(result);
141    SLmillibel mixVolumeLevelDefault;
142    result = (*mixVolume)->GetVolumeLevel(mixVolume, &mixVolumeLevelDefault);
143    check(result);
144    printf("default mix volume level = %d\n", mixVolumeLevelDefault);
145#endif
146
147    printf("numPathnames=%d\n", numPathnames);
148    printf("numPlayers=%d\n", numPlayers);
149    Player *p;
150
151    // create all the players
152    for (i = 0; i < numPlayers; ++i) {
153        const SLInterfaceID player_ids[] = {SL_IID_PLAY, SL_IID_VOLUME, SL_IID_SEEK};
154        const SLboolean player_req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
155        p = &players[i];
156        SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, (SLchar *) pathnames[i % numPathnames]};
157        SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
158        SLDataSource audioSrc = {&locURI, &dfMIME};
159        SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject};
160        SLDataSink audioSnk = {&locOutputMix, NULL};
161        result = (*engineEngine)->CreateAudioPlayer(engineEngine, &p->mPlayerObject, &audioSrc,
162            &audioSnk, 3, player_ids, player_req);
163        check(result);
164        result = (*p->mPlayerObject)->Realize(p->mPlayerObject, SL_BOOLEAN_FALSE);
165        check(result);
166        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_PLAY, &p->mPlayerPlay);
167        check(result);
168        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_VOLUME,
169            &p->mPlayerVolume);
170        check(result);
171        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_SEEK, &p->mPlayerSeek);
172        check(result);
173        result = (*p->mPlayerPlay)->GetDuration(p->mPlayerPlay, &p->mPlayerDuration);
174        check(result);
175        printf("player %d duration %d\n", (int) i, (int) p->mPlayerDuration);
176    }
177
178    // now loop randomly doing things to the players
179    for (;;) {
180        SLmillisecond delay = 100 + (rand() & 1023);
181        printf("sleep %u\n", (unsigned) delay);
182        usleep(delay * 1000);
183        i = (rand() & 0x7FFFFFFF) % numPlayers;
184        printf("player %d ", i);
185        p = &players[i];
186        SLuint32 state;
187        result = (*p->mPlayerPlay)->GetPlayState(p->mPlayerPlay, &state);
188        check(result);
189        printf("state = ");
190        switch (state) {
191        case SL_PLAYSTATE_STOPPED:
192            printf("STOPPED");
193            break;
194        case SL_PLAYSTATE_PAUSED:
195            printf("PAUSED");
196            break;
197        case SL_PLAYSTATE_PLAYING:
198            printf("PLAYING");
199            break;
200        default:
201            printf("%u", (unsigned) state);
202            break;
203        }
204        printf("\n");
205        if (state == SL_PLAYSTATE_STOPPED || state == SL_PLAYSTATE_PAUSED) {
206            SLmillibel volumeLevel = -((rand() & 0x7FFFFFFF) % ((SL_MILLIBEL_MIN + 1) / 10));
207            printf("volume %d\n", volumeLevel);
208            result = (*p->mPlayerVolume)->SetVolumeLevel(p->mPlayerVolume, volumeLevel);
209            check(result);
210            result = (*p->mPlayerVolume)->EnableStereoPosition(p->mPlayerVolume, SL_BOOLEAN_TRUE);
211            check(result);
212            SLpermille stereoPosition = ((rand() & 0x7FFFFFFF) % 2001) - 1000;
213            printf("position %d\n", stereoPosition);
214            result = (*p->mPlayerVolume)->SetStereoPosition(p->mPlayerVolume, stereoPosition);
215            check(result);
216            if (state != SL_PLAYSTATE_STOPPED) {
217                result = (*p->mPlayerSeek)->SetPosition(p->mPlayerSeek, 0, SL_SEEKMODE_FAST);
218                check(result);
219            }
220            result = (*p->mPlayerPlay)->SetPlayState(p->mPlayerPlay, SL_PLAYSTATE_PLAYING);
221            check(result);
222        }
223        if ((playTimeInMilliseconds > 0) && ((playTimeInMilliseconds -= delay) < 0))
224            break;
225    }
226
227    for (i = 0; i < numPlayers; ++i) {
228        SLObjectItf playerObject = players[i].mPlayerObject;
229        (*playerObject)->Destroy(playerObject);
230    }
231    (*mixObject)->Destroy(mixObject);
232    (*engineObject)->Destroy(engineObject);
233
234    return EXIT_SUCCESS;
235}
236