multiplay.c revision 4c71179974933c5c36cbfc3e8227c8df63248d91
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
25// Describes the state of one player
26
27typedef struct {
28    SLObjectItf mPlayerObject;
29    SLPlayItf mPlayerPlay;
30    SLSeekItf mPlayerSeek;
31    SLVolumeItf mPlayerVolume;
32    SLmillisecond mPlayerDuration;
33} Player;
34
35// Strings corresponding to result codes; FIXME should move to a common test library
36
37static const char *result_strings[] = {
38    "SUCCESS",
39    "PRECONDITIONS_VIOLATED",
40    "PARAMETER_INVALID",
41    "MEMORY_FAILURE",
42    "RESOURCE_ERROR",
43    "RESOURCE_LOST",
44    "IO_ERROR",
45    "BUFFER_INSUFFICIENT",
46    "CONTENT_CORRUPTED",
47    "CONTENT_UNSUPPORTED",
48    "CONTENT_NOT_FOUND",
49    "PERMISSION_DENIED",
50    "FEATURE_UNSUPPORTED",
51    "INTERNAL_ERROR",
52    "UNKNOWN_ERROR",
53    "OPERATION_ABORTED",
54    "CONTROL_LOST"
55};
56
57// Convert result to string; FIXME should move to common test library
58
59static const char *result_to_string(SLresult result)
60{
61    static char buffer[32];
62    if ( /* result >= 0 && */ result < sizeof(result_strings) / sizeof(result_strings[0]))
63        return result_strings[result];
64    sprintf(buffer, "%d", (int) result);
65    return buffer;
66}
67
68// Compare result against expected and exit suddenly if wrong
69
70void check2(SLresult result, int line)
71{
72    if (SL_RESULT_SUCCESS != result) {
73        fprintf(stderr, "error %s at line %d\n", result_to_string(result), line);
74        exit(EXIT_FAILURE);
75    }
76}
77
78// Same as above but automatically adds the source code line number
79
80#define check(result) check2(result, __LINE__)
81
82// Main program
83
84int main(int argc, char **argv)
85{
86    int i;
87    const char *arg;
88    int numPlayers = 0;
89    SLmillibel mixVolumeLevel = 0;
90    for (i = 1; i < argc; ++i) {
91        arg = argv[i];
92        if (arg[0] != '-')
93            break;
94        if (!strncmp(arg, "-n", 2))
95            numPlayers = atoi(&arg[2]);
96        else if (!strncmp(arg, "-v", 2))
97            mixVolumeLevel = atoi(&arg[2]);
98        else
99            fprintf(stderr, "unknown option: %s\n", arg);
100    }
101    int numPathnames = argc - i;
102    if (numPathnames <= 0) {
103        fprintf(stderr, "usage: %s file.wav ...\n", argv[0]);
104        return EXIT_FAILURE;
105    }
106    if (numPlayers <= 0)
107        numPlayers = numPathnames;
108    Player *players = (Player *) malloc(sizeof(Player) * numPlayers);
109    assert(NULL != players);
110    char **pathnames = &argv[i];
111    SLresult result;
112
113    // engine
114    const SLInterfaceID engine_ids[] = {SL_IID_ENGINE};
115    const SLboolean engine_req[] = {SL_BOOLEAN_TRUE};
116    SLObjectItf engineObject;
117    result = slCreateEngine(&engineObject, 0, NULL, 1, engine_ids, engine_req);
118    check(result);
119    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
120    check(result);
121    SLEngineItf engineEngine;
122    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
123    check(result);
124
125    // mixer
126    const SLInterfaceID mix_ids[] = {SL_IID_VOLUME};
127    const SLboolean mix_req[] = {SL_BOOLEAN_TRUE};
128    SLObjectItf mixObject;
129    result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, 1, mix_ids, mix_req);
130    check(result);
131    result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
132    check(result);
133    SLVolumeItf mixVolume;
134    result = (*mixObject)->GetInterface(mixObject, SL_IID_VOLUME, &mixVolume);
135    check(result);
136    SLmillibel mixVolumeLevelDefault;
137    result = (*mixVolume)->GetVolumeLevel(mixVolume, &mixVolumeLevelDefault);
138    check(result);
139    printf("default mix volume level = %d\n", mixVolumeLevelDefault);
140
141    printf("numPathnames=%d\n", numPathnames);
142    printf("numPlayers=%d\n", numPlayers);
143    Player *p;
144
145    // create all the players
146    for (i = 0; i < numPlayers; ++i) {
147        const SLInterfaceID player_ids[] = {SL_IID_PLAY, SL_IID_VOLUME, SL_IID_SEEK};
148        const SLboolean player_req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
149        p = &players[i];
150        SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, (SLchar *) pathnames[i % numPathnames]};
151        SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
152        SLDataSource audioSrc = {&locURI, &dfMIME};
153        SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, mixObject};
154        SLDataSink audioSnk = {&locOutputMix, NULL};
155        result = (*engineEngine)->CreateAudioPlayer(engineEngine, &p->mPlayerObject, &audioSrc,
156            &audioSnk, 3, player_ids, player_req);
157        check(result);
158        result = (*p->mPlayerObject)->Realize(p->mPlayerObject, SL_BOOLEAN_FALSE);
159        check(result);
160        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_PLAY, &p->mPlayerPlay);
161        check(result);
162        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_VOLUME,
163            &p->mPlayerVolume);
164        check(result);
165        result = (*p->mPlayerObject)->GetInterface(p->mPlayerObject, SL_IID_SEEK, &p->mPlayerSeek);
166        check(result);
167        result = (*p->mPlayerPlay)->GetDuration(p->mPlayerPlay, &p->mPlayerDuration);
168        check(result);
169        printf("player %d duration %d\n", (int) i, (int) p->mPlayerDuration);
170    }
171
172    // now loop randomly doing things to the players
173    for (;;) {
174        SLmillisecond delay = 100 + (rand() & 1023);
175        printf("sleep %u\n", (unsigned) delay);
176        usleep(delay * 1000);
177        i = (rand() & 0x7FFFFFFF) % numPlayers;
178        printf("player %d ", i);
179        p = &players[i];
180        SLuint32 state;
181        result = (*p->mPlayerPlay)->GetPlayState(p->mPlayerPlay, &state);
182        check(result);
183        printf("state = ");
184        switch (state) {
185        case SL_PLAYSTATE_STOPPED:
186            printf("STOPPED");
187            break;
188        case SL_PLAYSTATE_PAUSED:
189            printf("PAUSED");
190            break;
191        case SL_PLAYSTATE_PLAYING:
192            printf("PLAYING");
193            break;
194        default:
195            printf("%u", (unsigned) state);
196            break;
197        }
198        printf("\n");
199        if (state == SL_PLAYSTATE_STOPPED || state == SL_PLAYSTATE_PAUSED) {
200            SLmillibel volumeLevel = -((rand() & 0x7FFFFFFF) % ((SL_MILLIBEL_MIN + 1) / 10));
201            printf("volume %d\n", volumeLevel);
202            result = (*p->mPlayerVolume)->SetVolumeLevel(p->mPlayerVolume, volumeLevel);
203            check(result);
204            result = (*p->mPlayerVolume)->EnableStereoPosition(p->mPlayerVolume, SL_BOOLEAN_TRUE);
205            check(result);
206            SLpermille stereoPosition = ((rand() & 0x7FFFFFFF) % 2001) - 1000;
207            printf("position %d\n", stereoPosition);
208            result = (*p->mPlayerVolume)->SetStereoPosition(p->mPlayerVolume, stereoPosition);
209            check(result);
210            if (state != SL_PLAYSTATE_STOPPED) {
211                result = (*p->mPlayerSeek)->SetPosition(p->mPlayerSeek, 0, SL_SEEKMODE_FAST);
212                check(result);
213            }
214            result = (*p->mPlayerPlay)->SetPlayState(p->mPlayerPlay, SL_PLAYSTATE_PLAYING);
215            check(result);
216        }
217    }
218
219    // FIXME It would be interesting to end the test on some condition (timer, key pressed) so it
220    // also exercises the destruction of the players, output mix and engine after this test has run.
221
222    // return EXIT_SUCCESS;
223}
224