Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ef24576 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 6954

* changes:
  New test player stub to load mock native players.
parents ffc34c13 8f5fcab0
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -19,8 +19,10 @@

#ifdef __cplusplus

#include <sys/types.h>
#include <ui/ISurface.h>
#include <utils/RefBase.h>
#include <utils/Errors.h>

#include <media/mediaplayer.h>
#include <media/AudioSystem.h>
@@ -33,7 +35,11 @@ enum player_type {
    PV_PLAYER = 1,
    SONIVOX_PLAYER = 2,
    VORBIS_PLAYER = 3,
    STAGEFRIGHT_PLAYER = 4
    STAGEFRIGHT_PLAYER = 4,
    // Test players are available only in the 'test' and 'eng' builds.
    // The shared library with the test player is passed passed as an
    // argument to the 'test:' url in the setDataSource call.
    TEST_PLAYER = 5,
};


+5 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \
    MediaRecorderClient.cpp \
    MediaPlayerService.cpp \
    MetadataRetrieverClient.cpp \
    TestPlayerStub.cpp \
    VorbisPlayer.cpp \
    MidiFile.cpp

@@ -28,6 +29,10 @@ LOCAL_SHARED_LIBRARIES := \
    libmedia \
    libandroid_runtime

ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += libdl
endif

LOCAL_C_INCLUDES := external/tremor/Tremor \
	$(call include-path-for, graphics corecg) \
	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+18 −2
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@
#include <string.h>

#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <cutils/properties.h> // for property_get

#include <utils/misc.h>

@@ -58,6 +58,8 @@
#include "MidiFile.h"
#include "VorbisPlayer.h"
#include <media/PVPlayer.h>
#include "TestPlayerStub.h"

#if USE_STAGEFRIGHT
#include "StagefrightPlayer.h"
#endif
@@ -68,6 +70,8 @@
#include <media/IOMX.h>
#endif



/* desktop Linux needs a little help with gettid() */
#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
#define __KERNEL__
@@ -656,6 +660,10 @@ static player_type getPlayerType(int fd, int64_t offset, int64_t length)

static player_type getPlayerType(const char* url)
{
    if (TestPlayerStub::canBeUsed(url)) {
        return TEST_PLAYER;
    }

    // use MidiFile for MIDI extensions
    int lenURL = strlen(url);
    for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
@@ -706,6 +714,10 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
                    "Should not be here, stagefright player not enabled.");
            break;
#endif
        case TEST_PLAYER:
            LOGV("Create Test Player stub");
            p = new TestPlayerStub();
            break;
    }
    if (p != NULL) {
        if (p->initCheck() == NO_ERROR) {
@@ -770,7 +782,11 @@ status_t MediaPlayerService::Client::setDataSource(const char *url)
        // now set data source
        LOGV(" setDataSource");
        mStatus = p->setDataSource(url);
        if (mStatus == NO_ERROR) mPlayer = p;
        if (mStatus == NO_ERROR) {
            mPlayer = p;
        } else {
            LOGE("  error: %d", mStatus);
        }
        return mStatus;
    }
}
+196 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 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.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "TestPlayerStub"
#include "utils/Log.h"

#include "TestPlayerStub.h"

#include <dlfcn.h>  // for dlopen/dlclose
#include <stdlib.h>
#include <string.h>
#include <cutils/properties.h>
#include <utils/Errors.h>  // for status_t

#include "media/MediaPlayerInterface.h"


namespace {
using android::status_t;
using android::MediaPlayerBase;

const char *kTestUrlScheme = "test:";
const char *kUrlParam = "url=";

const char *kBuildTypePropName = "ro.build.type";
const char *kEngBuild = "eng";
const char *kTestBuild = "test";

// @return true if the current build is 'eng' or 'test'.
bool isTestBuild()
{
    char prop[PROPERTY_VALUE_MAX] = { '\0', };

    property_get(kBuildTypePropName, prop, '\0');
    return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
}

// @return true if the url scheme is 'test:'
bool isTestUrl(const char *url)
{
    return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
}

}  // anonymous namespace

namespace android {

TestPlayerStub::TestPlayerStub()
    :mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
     mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
     mPlayer(NULL) { }

TestPlayerStub::~TestPlayerStub()
{
    resetInternal();
}

status_t TestPlayerStub::initCheck()
{
    return isTestBuild() ? OK : INVALID_OPERATION;
}

// Parse mUrl to get:
// * The library to be dlopened.
// * The url to be passed to the real setDataSource impl.
//
// mUrl is expected to be in following format:
//
// test:<name of the .so>?url=<url for setDataSource>
//
// The value of the url parameter is treated as a string (no
// unescaping of illegal charaters).
status_t TestPlayerStub::parseUrl()
{
    if (strlen(mUrl) < strlen(kTestUrlScheme)) {
        resetInternal();
        return BAD_VALUE;
    }

    char *i = mUrl + strlen(kTestUrlScheme);

    mFilename = i;

    while (*i != '\0' && *i != '?') {
        ++i;
    }

    if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
        resetInternal();
        return BAD_VALUE;
    }
    *i = '\0';  // replace '?' to nul-terminate mFilename

    mContentUrl = i + 1 + strlen(kUrlParam);
    return OK;
}

// Load the dynamic library.
// Create the test player.
// Call setDataSource on the test player with the url in param.
status_t TestPlayerStub::setDataSource(const char *url)
{
    if (!isTestUrl(url) || NULL != mHandle) {
        return INVALID_OPERATION;
    }

    mUrl = strdup(url);

    status_t status = parseUrl();

    if (OK != status) {
        resetInternal();
        return status;
    }

    ::dlerror();  // Clears any pending error.

    // Load the test player from the url. dlopen will fail if the lib
    // is not there. dls are under /system/lib
    // None of the entry points should be NULL.
    mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
    if (!mHandle) {
        LOGE("dlopen failed: %s", ::dlerror());
        resetInternal();
        return UNKNOWN_ERROR;
    }

    // Load the 2 entry points to create and delete instances.
    const char *err;
    mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
                                                    "newPlayer"));
    err = ::dlerror();
    if (err || mNewPlayer == NULL) {
        // if err is NULL the string <null> is inserted in the logs =>
        // mNewPlayer was NULL.
        LOGE("dlsym for newPlayer failed %s", err);
        resetInternal();
        return UNKNOWN_ERROR;
    }

    mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
                                                          "deletePlayer"));
    err = ::dlerror();
    if (err || mDeletePlayer == NULL) {
        LOGE("dlsym for deletePlayer failed %s", err);
        resetInternal();
        return UNKNOWN_ERROR;
    }

    mPlayer = (*mNewPlayer)();
    return mPlayer->setDataSource(mContentUrl);
}

// Internal cleanup.
status_t TestPlayerStub::resetInternal()
{
    if(mUrl) {
        free(mUrl);
        mUrl = NULL;
    }
    mFilename = NULL;
    mContentUrl = NULL;

    if (mPlayer) {
        LOG_ASSERT(mDeletePlayer != NULL);
        (*mDeletePlayer)(mPlayer);
        mPlayer = NULL;
    }

    if (mHandle) {
        ::dlclose(mHandle);
        mHandle = NULL;
    }
    return OK;
}

/* static */ bool TestPlayerStub::canBeUsed(const char *url)
{
    return isTestBuild() && isTestUrl(url);
}

}  // namespace android
+119 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 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.
 */

#ifndef ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
#define ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__

#include <media/MediaPlayerInterface.h>
#include <utils/Errors.h>

namespace android {
class MediaPlayerBase;  // in media/MediaPlayerInterface.h

// Wrapper around a test media player that gets dynamically loaded.
//
// The URL passed to setDataSource has this format:
//
//   test:<name of the .so>?url=<url for the real setDataSource impl.>
//
// e.g:
//   test:invoke_test_media_player.so?url=http://youtube.com/
//   test:invoke_test_media_player.so?url=speedtest
//
// TestPlayerStub::setDataSource loads the library in the test url. 2
// entry points with C linkage are expected. One to create the test
// player and one to destroy it.
//
// extern "C" android::MediaPlayerBase* newPlayer();
// extern "C" android::status_t deletePlayer(android::MediaPlayerBase *p);
//
// Once the test player has been loaded, its setDataSource
// implementation is called with the value of the 'url' parameter.
//
// typical usage in a java test:
// ============================
//
//  MediaPlayer p = new MediaPlayer();
//  p.setDataSource("test:invoke_mock_media_player.so?url=http://youtube.com");
//  p.prepare();
//  ...
//  p.release();

class TestPlayerStub : public MediaPlayerInterface {
  public:
    typedef MediaPlayerBase* (*NEW_PLAYER)();
    typedef status_t (*DELETE_PLAYER)(MediaPlayerBase *);

    TestPlayerStub();
    virtual ~TestPlayerStub();

    // Called right after the constructor. Check if the current build
    // allows test players.
    virtual status_t initCheck();

    // @param url Should be a test url. See class comment.
    virtual status_t setDataSource(const char* url);

    // Test player for a file descriptor source is not supported.
    virtual status_t setDataSource(int, int64_t, int64_t)  {
        return INVALID_OPERATION;
    }


    // All the methods below wrap the mPlayer instance.
    virtual status_t setVideoSurface(const android::sp<android::ISurface>& s)  {
        return mPlayer->setVideoSurface(s);
    }
    virtual status_t prepare() {return mPlayer->prepare();}
    virtual status_t prepareAsync()  {return mPlayer->prepareAsync();}
    virtual status_t start()  {return mPlayer->start();}
    virtual status_t stop()  {return mPlayer->stop();}
    virtual status_t pause()  {return mPlayer->pause();}
    virtual bool isPlaying() {return mPlayer->isPlaying();}
    virtual status_t seekTo(int msec) {return mPlayer->seekTo(msec);}
    virtual status_t getCurrentPosition(int *p)  {
        return mPlayer->getCurrentPosition(p);
    }
    virtual status_t getDuration(int *d)  {return mPlayer->getDuration(d);}
    virtual status_t reset() {return mPlayer->reset();}
    virtual status_t setLooping(int b)  {return mPlayer->setLooping(b);}
    virtual player_type playerType() {return mPlayer->playerType();}
    virtual status_t invoke(const android::Parcel& in, android::Parcel *out) {
        return mPlayer->invoke(in, out);
    }


    // @return true if the current build is 'eng' or 'test' and the
    //              url's scheme is 'test:'
    static bool canBeUsed(const char *url);

  private:
    // Release the player, dlclose the library.
    status_t resetInternal();
    status_t parseUrl();

    char *mUrl;                // test:foo.so?url=http://bar
    char *mFilename;           // foo.so
    char *mContentUrl;         // http://bar
    void *mHandle;             // returned by dlopen
    NEW_PLAYER    mNewPlayer;
    DELETE_PLAYER mDeletePlayer;
    MediaPlayerBase *mPlayer;  // wrapped player
};

}  // namespace android

#endif
Loading