Loading include/media/MediaPlayerInterface.h +7 −1 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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, }; Loading media/libmediaplayerservice/Android.mk +5 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \ MediaRecorderClient.cpp \ MediaPlayerService.cpp \ MetadataRetrieverClient.cpp \ TestPlayerStub.cpp \ VorbisPlayer.cpp \ MidiFile.cpp Loading @@ -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 Loading media/libmediaplayerservice/MediaPlayerService.cpp +18 −2 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -58,6 +58,8 @@ #include "MidiFile.h" #include "VorbisPlayer.h" #include <media/PVPlayer.h> #include "TestPlayerStub.h" #if USE_STAGEFRIGHT #include "StagefrightPlayer.h" #endif Loading @@ -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__ Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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; } } Loading media/libmediaplayerservice/TestPlayerStub.cpp 0 → 100644 +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 media/libmediaplayerservice/TestPlayerStub.h 0 → 100644 +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
include/media/MediaPlayerInterface.h +7 −1 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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, }; Loading
media/libmediaplayerservice/Android.mk +5 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \ MediaRecorderClient.cpp \ MediaPlayerService.cpp \ MetadataRetrieverClient.cpp \ TestPlayerStub.cpp \ VorbisPlayer.cpp \ MidiFile.cpp Loading @@ -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 Loading
media/libmediaplayerservice/MediaPlayerService.cpp +18 −2 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -58,6 +58,8 @@ #include "MidiFile.h" #include "VorbisPlayer.h" #include <media/PVPlayer.h> #include "TestPlayerStub.h" #if USE_STAGEFRIGHT #include "StagefrightPlayer.h" #endif Loading @@ -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__ Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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; } } Loading
media/libmediaplayerservice/TestPlayerStub.cpp 0 → 100644 +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
media/libmediaplayerservice/TestPlayerStub.h 0 → 100644 +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