123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- /*
- * 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.
- */
- /*
- * Copyright (c) 2009 The Khronos Group Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and /or associated documentation files (the "Materials "), to deal in the
- * Materials without restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies of the Materials,
- * and to permit persons to whom the Materials are furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Materials.
- *
- * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN THE
- * MATERIALS.
- */
- #define LOG_NDEBUG 0
- #define LOG_TAG "slesTestPlayUri"
- #include <utils/Log.h>
- #include <getopt.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/time.h>
- #include <gtest/gtest.h>
- #include <SLES/OpenSLES.h>
- #define MAX_NUMBER_INTERFACES 3
- #define MAX_NUMBER_OUTPUT_DEVICES 6
- //The expected playback duration
- const int MP3_DURATION = 71030; //71 secs
- //-----------------------------------------------------------------
- /* Checks for error. If any errors exit the application! */
- void CheckErr( SLresult res )
- {
- if ( res != SL_RESULT_SUCCESS ) {
- fprintf(stderr, "%u SL failure, exiting\n", res);
- //Fail the test case
- ASSERT_TRUE(false);
- }
- }
- //-----------------------------------------------------------------
- /* PrefetchStatusItf callback for an audio player */
- void PrefetchEventCallback( SLPrefetchStatusItf caller, void *pContext __unused, SLuint32 event)
- {
- SLpermille level = 0;
- (*caller)->GetFillLevel(caller, &level);
- SLuint32 status;
- fprintf(stdout, "\t\tPrefetchEventCallback: received event %u\n", event);
- (*caller)->GetPrefetchStatus(caller, &status);
- if ((event & (SL_PREFETCHEVENT_STATUSCHANGE|SL_PREFETCHEVENT_FILLLEVELCHANGE))
- && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
- fprintf(stderr, "\t\tPrefetchEventCallback: Error while prefetching data, exiting\n");
- ASSERT_TRUE(false);
- }
- if (event & SL_PREFETCHEVENT_FILLLEVELCHANGE) {
- fprintf(stdout, "\t\tPrefetchEventCallback: Buffer fill level is = %d\n", level);
- }
- if (event & SL_PREFETCHEVENT_STATUSCHANGE) {
- fprintf(stdout, "\t\tPrefetchEventCallback: Prefetch Status is = %u\n", status);
- }
- }
- //-----------------------------------------------------------------
- /* Play some music from a URI */
- void TestPlayUri( SLObjectItf sl, const char* path)
- {
- SLEngineItf EngineItf;
- SLresult res;
- SLDataSource audioSource;
- SLDataLocator_URI uri;
- SLDataFormat_MIME mime;
- SLDataSink audioSink;
- SLDataLocator_OutputMix locator_outputmix;
- SLObjectItf player;
- SLPlayItf playItf;
- SLVolumeItf volItf;
- SLPrefetchStatusItf prefetchItf;
- SLObjectItf OutputMix;
- SLboolean required[MAX_NUMBER_INTERFACES];
- SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
- /* Get the SL Engine Interface which is implicit */
- res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
- CheckErr(res);
- /* Initialize arrays required[] and iidArray[] */
- for (int i=0 ; i < MAX_NUMBER_INTERFACES ; i++) {
- required[i] = SL_BOOLEAN_FALSE;
- iidArray[i] = SL_IID_NULL;
- }
- // Set arrays required[] and iidArray[] for VOLUME and PREFETCHSTATUS interface
- required[0] = SL_BOOLEAN_TRUE;
- iidArray[0] = SL_IID_VOLUME;
- required[1] = SL_BOOLEAN_TRUE;
- iidArray[1] = SL_IID_PREFETCHSTATUS;
- // Create Output Mix object to be used by player
- res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
- iidArray, required); CheckErr(res);
- // Realizing the Output Mix object in synchronous mode.
- res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
- CheckErr(res);
- /* Setup the data source structure for the URI */
- uri.locatorType = SL_DATALOCATOR_URI;
- uri.URI = (SLchar*) path;
- mime.formatType = SL_DATAFORMAT_MIME;
- mime.mimeType = (SLchar*)NULL;
- mime.containerType = SL_CONTAINERTYPE_UNSPECIFIED;
- audioSource.pFormat = (void *)&mime;
- audioSource.pLocator = (void *)&uri;
- /* Setup the data sink structure */
- locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
- locator_outputmix.outputMix = OutputMix;
- audioSink.pLocator = (void *)&locator_outputmix;
- audioSink.pFormat = NULL;
- /* Create the audio player */
- res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
- &audioSource, &audioSink, 2, iidArray, required); CheckErr(res);
- /* Realizing the player in synchronous mode. */
- res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
- /* Get interfaces */
- res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
- CheckErr(res);
- res = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volItf);
- CheckErr(res);
- res = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void*)&prefetchItf);
- CheckErr(res);
- res = (*prefetchItf)->RegisterCallback(prefetchItf, PrefetchEventCallback, &prefetchItf);
- CheckErr(res);
- res = (*prefetchItf)->SetCallbackEventsMask(prefetchItf,
- SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
- /* Display duration */
- SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
- res = (*playItf)->GetDuration(playItf, &durationInMsec);
- CheckErr(res);
- /* Set the player volume */
- res = (*volItf)->SetVolumeLevel( volItf, -300);
- CheckErr(res);
- /* Play the URI */
- /* first cause the player to prefetch the data */
- res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PAUSED );
- CheckErr(res);
- /* wait until there's data to play */
- //SLpermille fillLevel = 0;
- SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
- SLuint32 timeOutIndex = 100; // 10s
- while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
- usleep(100 * 1000);
- (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
- timeOutIndex--;
- }
- if (timeOutIndex == 0) {
- fprintf(stderr, "Error: Failed to prefetch data in time, exiting\n");
- ASSERT_TRUE(false);
- // goto destroyRes;
- }
- /* Display duration again, */
- res = (*playItf)->GetDuration(playItf, &durationInMsec);
- CheckErr(res);
- if (durationInMsec == SL_TIME_UNKNOWN) {
- fprintf(stderr, "Error: GetDuration returned SL_TIME_UNKNOWN (after prefetch completed)\n");
- ASSERT_TRUE(false);
- }
- SLint32 durationDiffMsec = durationInMsec - MP3_DURATION;
- if (durationDiffMsec < 0) { durationDiffMsec *= -1; }
- if (durationDiffMsec > (MP3_DURATION/20)) {
- fprintf(stderr, "Error: GetDuration returned %d, more than 5percent off from expected %d\n",
- durationInMsec, MP3_DURATION);
- ASSERT_TRUE(false);
- }
- res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
- CheckErr(res);
- /* Play for the song duration*/
- usleep(MP3_DURATION * 1000);
- /* Validate the play position*/
- SLmillisecond currentPositionInMsec = SL_TIME_UNKNOWN;
- res = (*playItf)->GetPosition(playItf, ¤tPositionInMsec);
- CheckErr(res);
- if (currentPositionInMsec == SL_TIME_UNKNOWN) {
- fprintf(stderr, "Error: GetPosition returns SL_TIME_UNKNOWN after expected duration\n");
- ASSERT_TRUE(false);
- } else if ( currentPositionInMsec <= 0 ||
- currentPositionInMsec > (MP3_DURATION * 1.1) ){
- fprintf(stderr, "Error: GetPosition returns %i, should be expected duration for test\n",
- (int) currentPositionInMsec);
- ASSERT_TRUE(false);
- }
- /* Make sure player is stopped */
- res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
- CheckErr(res);
- //destroyRes:
- /* Destroy the player */
- (*player)->Destroy(player);
- /* Destroy Output Mix object */
- (*OutputMix)->Destroy(OutputMix);
- fprintf(stdout, "End of test reached\n");
- }
- // The fixture for testing class MimeUri
- class MimeUri: public ::testing::Test {
- public:
- SLresult res;
- SLObjectItf sl;
- protected:
- MimeUri() {
- // You can do set-up work for each test here.
- SLEngineOption EngineOption[] = { { (SLuint32) SL_ENGINEOPTION_THREADSAFE,
- (SLuint32) SL_BOOLEAN_TRUE } };
- res = slCreateEngine(&sl, 1, EngineOption, 0, NULL, NULL);
- CheckErr(res);
- /* Realizing the SL Engine in synchronous mode. */
- res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
- CheckErr(res);
- }
- virtual ~MimeUri() {
- // You can do clean-up work that doesn't throw exceptions here.
- (*sl)->Destroy(sl);
- }
- virtual void SetUp() {
- // Code here will be called immediately after the constructor (right
- // before each test).
- }
- virtual void TearDown() {
- // Code here will be called immediately after each test (right
- // before the destructor).
- }
- };
- TEST_F(MimeUri, testPlayAbsPath){
- TestPlayUri(sl, "/sdcard/media_api/music/MP3_256kbps_2ch.mp3");
- }
- TEST_F(MimeUri, testPlayfilePath){
- TestPlayUri(sl, "file:///sdcard/media_api/music/MP3_256kbps_2ch.mp3");
- }
- //-----------------------------------------------------------------
- int main(int argc, char **argv)
- {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
- }
|