114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania/*
214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * Copyright (C) 2009 The Android Open Source Project
314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania *
414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * Licensed under the Apache License, Version 2.0 (the "License");
514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * you may not use this file except in compliance with the License.
614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * You may obtain a copy of the License at
714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania *
814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania *      http://www.apache.org/licenses/LICENSE-2.0
914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania *
1014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * Unless required by applicable law or agreed to in writing, software
1114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * distributed under the License is distributed on an "AS IS" BASIS,
1214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * See the License for the specific language governing permissions and
1414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania * limitations under the License.
1514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania */
1614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
1714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania//#define LOG_NDEBUG 0
1814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#define LOG_TAG "TestPlayerStub"
1914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#include "utils/Log.h"
2014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
2114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#include "TestPlayerStub.h"
2214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
2314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#include <dlfcn.h>  // for dlopen/dlclose
2414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#include <stdlib.h>
2514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#include <string.h>
2614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#include <cutils/properties.h>
2714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#include <utils/Errors.h>  // for status_t
2814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
2914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania#include "media/MediaPlayerInterface.h"
3014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
3114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
3214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catanianamespace {
3314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniausing android::status_t;
3414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniausing android::MediaPlayerBase;
3514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
3614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniaconst char *kTestUrlScheme = "test:";
3714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniaconst char *kUrlParam = "url=";
3814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
3914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniaconst char *kBuildTypePropName = "ro.build.type";
4014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniaconst char *kEngBuild = "eng";
4114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniaconst char *kTestBuild = "test";
4214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
4314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// @return true if the current build is 'eng' or 'test'.
4414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniabool isTestBuild()
4514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania{
4614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    char prop[PROPERTY_VALUE_MAX] = { '\0', };
4714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
482d0ac425564ff9882ebaac5267d1a04d4af67d00Bernhard Rosenkränzer    property_get(kBuildTypePropName, prop, "\0");
4914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
5014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}
5114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
5214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// @return true if the url scheme is 'test:'
5314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniabool isTestUrl(const char *url)
5414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania{
5514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
5614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}
5714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
5814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}  // anonymous namespace
5914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
6014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catanianamespace android {
6114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
6214d2747c7e54037e267bcff78b29e65b2181f0faNicolas CataniaTestPlayerStub::TestPlayerStub()
6314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    :mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
6414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania     mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
6514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania     mPlayer(NULL) { }
6614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
6714d2747c7e54037e267bcff78b29e65b2181f0faNicolas CataniaTestPlayerStub::~TestPlayerStub()
6814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania{
6914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    resetInternal();
7014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}
7114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
7214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniastatus_t TestPlayerStub::initCheck()
7314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania{
7414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    return isTestBuild() ? OK : INVALID_OPERATION;
7514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}
7614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
7714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// Parse mUrl to get:
7814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// * The library to be dlopened.
7914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// * The url to be passed to the real setDataSource impl.
8014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania//
8114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// mUrl is expected to be in following format:
8214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania//
8314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// test:<name of the .so>?url=<url for setDataSource>
8414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania//
8514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// The value of the url parameter is treated as a string (no
8614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// unescaping of illegal charaters).
8714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniastatus_t TestPlayerStub::parseUrl()
8814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania{
8914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (strlen(mUrl) < strlen(kTestUrlScheme)) {
9014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        resetInternal();
9114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        return BAD_VALUE;
9214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
9314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
9414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    char *i = mUrl + strlen(kTestUrlScheme);
9514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
9614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mFilename = i;
9714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
9814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    while (*i != '\0' && *i != '?') {
9914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        ++i;
10014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
10114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
10214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
10314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        resetInternal();
10414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        return BAD_VALUE;
10514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
10614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    *i = '\0';  // replace '?' to nul-terminate mFilename
10714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
10814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mContentUrl = i + 1 + strlen(kUrlParam);
10914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    return OK;
11014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}
11114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
11214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// Load the dynamic library.
11314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// Create the test player.
11414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// Call setDataSource on the test player with the url in param.
1152db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huberstatus_t TestPlayerStub::setDataSource(
1161b86fe063badb5f28c467ade39be0f4008688947Andreas Huber        const sp<IMediaHTTPService> &httpService,
1171b86fe063badb5f28c467ade39be0f4008688947Andreas Huber        const char *url,
1181b86fe063badb5f28c467ade39be0f4008688947Andreas Huber        const KeyedVector<String8, String8> *headers) {
11914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (!isTestUrl(url) || NULL != mHandle) {
12014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        return INVALID_OPERATION;
12114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
12214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
12314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mUrl = strdup(url);
12414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
12514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    status_t status = parseUrl();
12614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
12714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (OK != status) {
12814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        resetInternal();
12914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        return status;
13014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
13114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
13214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    ::dlerror();  // Clears any pending error.
13314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
13414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    // Load the test player from the url. dlopen will fail if the lib
13514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    // is not there. dls are under /system/lib
13614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    // None of the entry points should be NULL.
13714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
13814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (!mHandle) {
13929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("dlopen failed: %s", ::dlerror());
14014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        resetInternal();
14114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        return UNKNOWN_ERROR;
14214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
14314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
14414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    // Load the 2 entry points to create and delete instances.
14514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    const char *err;
14614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
14714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania                                                    "newPlayer"));
14814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    err = ::dlerror();
14914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (err || mNewPlayer == NULL) {
15014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        // if err is NULL the string <null> is inserted in the logs =>
15114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        // mNewPlayer was NULL.
15229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("dlsym for newPlayer failed %s", err);
15314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        resetInternal();
15414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        return UNKNOWN_ERROR;
15514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
15614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
15714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
15814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania                                                          "deletePlayer"));
15914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    err = ::dlerror();
16014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (err || mDeletePlayer == NULL) {
16129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("dlsym for deletePlayer failed %s", err);
16214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        resetInternal();
16314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        return UNKNOWN_ERROR;
16414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
16514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
16614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mPlayer = (*mNewPlayer)();
1671b86fe063badb5f28c467ade39be0f4008688947Andreas Huber    return mPlayer->setDataSource(httpService, mContentUrl, headers);
16814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}
16914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
17014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania// Internal cleanup.
17114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Cataniastatus_t TestPlayerStub::resetInternal()
17214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania{
17314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if(mUrl) {
17414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        free(mUrl);
17514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        mUrl = NULL;
17614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
17714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mFilename = NULL;
17814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    mContentUrl = NULL;
17914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
18014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (mPlayer) {
181c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block        ALOG_ASSERT(mDeletePlayer != NULL, "mDeletePlayer is null");
18214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        (*mDeletePlayer)(mPlayer);
18314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        mPlayer = NULL;
18414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
18514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
18614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    if (mHandle) {
18714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        ::dlclose(mHandle);
18814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania        mHandle = NULL;
18914d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    }
19014d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    return OK;
19114d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}
19214d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
19314d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania/* static */ bool TestPlayerStub::canBeUsed(const char *url)
19414d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania{
19514d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania    return isTestBuild() && isTestUrl(url);
19614d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}
19714d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania
19814d2747c7e54037e267bcff78b29e65b2181f0faNicolas Catania}  // namespace android
199