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 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/time.h>
22 #include <fcntl.h>
23 
24 #include <SLES/OpenSLES.h>
25 #include <SLES/OpenSLES_Android.h>
26 
27 
28 #define MAX_NUMBER_INTERFACES 3
29 
30 #define TEST_MUTE 0
31 #define TEST_SOLO 1
32 
33 static int testMode;
34 //-----------------------------------------------------------------
35 /* Exits the application if an error is encountered */
36 #define ExitOnError(x) ExitOnErrorFunc(x,__LINE__)
37 
ExitOnErrorFunc(SLresult result,int line)38 void ExitOnErrorFunc( SLresult result , int line)
39 {
40     if (SL_RESULT_SUCCESS != result) {
41         fprintf(stdout, "%u error code encountered at line %d, exiting\n", result, line);
42         exit(EXIT_FAILURE);
43     }
44 }
45 
46 
47 //-----------------------------------------------------------------
48 
49 /* Play an audio path by opening a file descriptor on that path  */
TestPlayPathFromFD(SLObjectItf sl,const char * path,SLAint64 offset,SLAint64 size)50 void TestPlayPathFromFD( SLObjectItf sl, const char* path, SLAint64 offset, SLAint64 size)
51 {
52     SLresult  result;
53     SLEngineItf EngineItf;
54 
55     /* Objects this application uses: one player and an ouput mix */
56     SLObjectItf  player, outputMix;
57 
58     /* Source of audio data to play */
59     SLDataSource            audioSource;
60     SLDataLocator_AndroidFD locatorFd;
61     SLDataFormat_MIME       mime;
62 
63     /* Data sinks for the audio player */
64     SLDataSink               audioSink;
65     SLDataLocator_OutputMix  locator_outputmix;
66 
67     /* Play and PrefetchStatus interfaces for the audio player */
68     SLPlayItf              playItf;
69     SLPrefetchStatusItf    prefetchItf;
70 
71     SLboolean required[MAX_NUMBER_INTERFACES];
72     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
73 
74     /* Get the SL Engine Interface which is implicit */
75     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
76     ExitOnError(result);
77 
78     /* Initialize arrays required[] and iidArray[] */
79     for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
80         required[i] = SL_BOOLEAN_FALSE;
81         iidArray[i] = SL_IID_NULL;
82     }
83 
84     /* ------------------------------------------------------ */
85     /* Configuration of the output mix  */
86 
87     /* Create Output Mix object to be used by the player */
88      result = (*EngineItf)->CreateOutputMix(EngineItf, &outputMix, 0, iidArray, required);
89      ExitOnError(result);
90 
91     /* Realize the Output Mix object in synchronous mode */
92     result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
93     ExitOnError(result);
94 
95     /* Setup the data sink structure */
96     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
97     locator_outputmix.outputMix   = outputMix;
98     audioSink.pLocator            = (void*)&locator_outputmix;
99     audioSink.pFormat             = NULL;
100 
101     /* ------------------------------------------------------ */
102     /* Configuration of the player  */
103 
104     /* Set arrays required[] and iidArray[] for SLPrefetchStatusItf interfaces */
105     /*  (SLPlayItf is implicit) */
106     required[0] = SL_BOOLEAN_TRUE;
107     iidArray[0] = SL_IID_PREFETCHSTATUS;
108 
109     /* Setup the data source structure for the URI */
110     locatorFd.locatorType = SL_DATALOCATOR_ANDROIDFD;
111     int fd = open(path, O_RDONLY);
112     if (fd == -1) {
113         perror(path);
114         exit(EXIT_FAILURE);
115     }
116     locatorFd.fd = (SLint32) fd;
117     locatorFd.length = size;
118     locatorFd.offset = offset;
119 
120     mime.formatType = SL_DATAFORMAT_MIME;
121     /*     this is how ignored mime information is specified, according to OpenSL ES spec
122      *     in 9.1.6 SLDataFormat_MIME and 8.23 SLMetadataTraversalItf GetChildInfo */
123     mime.mimeType      = (SLchar*)NULL;
124     mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
125 
126     audioSource.pFormat  = (void*)&mime;
127     audioSource.pLocator = (void*)&locatorFd;
128 
129     /* Create the audio player */
130     result = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, &audioSource, &audioSink, 1,
131             iidArray, required);
132     ExitOnError(result);
133 
134     /* Realize the player in synchronous mode. */
135     result = (*player)->Realize(player, SL_BOOLEAN_FALSE); ExitOnError(result);
136     fprintf(stdout, "URI example: after Realize\n");
137 
138     /* Get the SLPlayItf, SLPrefetchStatusItf and SLAndroidStreamTypeItf interfaces for the player*/
139     result = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
140     ExitOnError(result);
141 
142     result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
143     ExitOnError(result);
144 
145     fprintf(stdout, "Player configured\n");
146 
147     /* ------------------------------------------------------ */
148     /* Playback and test */
149 
150     /* Start the data prefetching by setting the player to the paused state */
151     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
152     ExitOnError(result);
153 
154     /* Wait until there's data to play */
155     SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
156     while (prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) {
157         usleep(100 * 1000);
158         (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
159         ExitOnError(result);
160     }
161 
162     /* Get duration */
163     SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
164     result = (*playItf)->GetDuration(playItf, &durationInMsec);
165     ExitOnError(result);
166     if (durationInMsec == SL_TIME_UNKNOWN) {
167         durationInMsec = 5000;
168     }
169 
170     /* Start playback */
171     result = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
172     ExitOnError(result);
173 
174     usleep(durationInMsec * 1000);
175 
176     /* Make sure player is stopped */
177     fprintf(stdout, "Stopping playback\n");
178     result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
179     ExitOnError(result);
180 
181     /* Destroy the player */
182     (*player)->Destroy(player);
183 
184     /* Destroy Output Mix object */
185     (*outputMix)->Destroy(outputMix);
186 
187     close(fd);
188 }
189 
190 //-----------------------------------------------------------------
main(int argc,char * const argv[])191 int main(int argc, char* const argv[])
192 {
193     SLresult    result;
194     SLObjectItf sl;
195 
196     fprintf(stdout, "OpenSL ES test %s: exercises SLPlayItf ", argv[0]);
197     fprintf(stdout, "and AudioPlayer with SLDataLocator_AndroidFD source / OutputMix sink\n");
198     fprintf(stdout, "Plays the sound file designated by the given path, ");
199     fprintf(stdout, "starting at the specified offset, and using the specified length.\n");
200     fprintf(stdout, "Omit the length of the file for it to be computed by the system.\n");
201 
202     if (argc < 3) {
203         fprintf(stdout, "Usage: \t%s path offsetInBytes [sizeInBytes]\n", argv[0]);
204         fprintf(stdout, "Example: \"%s /sdcard/my.mp3 0 344460\" \n", argv[0]);
205         exit(EXIT_FAILURE);
206     }
207 
208     SLEngineOption EngineOption[] = {
209             {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
210     };
211 
212     result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
213     ExitOnError(result);
214 
215     /* Realizing the SL Engine in synchronous mode. */
216     result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
217     ExitOnError(result);
218 
219     if (argc == 3) {
220         fprintf(stdout, "no file size given, using SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE\n");
221         TestPlayPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]),
222                 SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE);
223     } else {
224         TestPlayPathFromFD(sl, argv[1], (SLAint64)atoi(argv[2]), (SLAint64)atoi(argv[3]));
225     }
226 
227     /* Shutdown OpenSL ES */
228     (*sl)->Destroy(sl);
229 
230     return EXIT_SUCCESS;
231 }
232