1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2009 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "TestPlayerStub"
19*ec779b8eSAndroid Build Coastguard Worker #include "utils/Log.h"
20*ec779b8eSAndroid Build Coastguard Worker
21*ec779b8eSAndroid Build Coastguard Worker #include "TestPlayerStub.h"
22*ec779b8eSAndroid Build Coastguard Worker
23*ec779b8eSAndroid Build Coastguard Worker #include <dlfcn.h> // for dlopen/dlclose
24*ec779b8eSAndroid Build Coastguard Worker #include <stdlib.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <string.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <cutils/properties.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <utils/Errors.h> // for status_t
28*ec779b8eSAndroid Build Coastguard Worker
29*ec779b8eSAndroid Build Coastguard Worker #include "media/MediaPlayerInterface.h"
30*ec779b8eSAndroid Build Coastguard Worker
31*ec779b8eSAndroid Build Coastguard Worker
32*ec779b8eSAndroid Build Coastguard Worker namespace {
33*ec779b8eSAndroid Build Coastguard Worker using android::status_t;
34*ec779b8eSAndroid Build Coastguard Worker using android::MediaPlayerBase;
35*ec779b8eSAndroid Build Coastguard Worker
36*ec779b8eSAndroid Build Coastguard Worker const char *kTestUrlScheme = "test:";
37*ec779b8eSAndroid Build Coastguard Worker const char *kUrlParam = "url=";
38*ec779b8eSAndroid Build Coastguard Worker
39*ec779b8eSAndroid Build Coastguard Worker const char *kBuildTypePropName = "ro.build.type";
40*ec779b8eSAndroid Build Coastguard Worker const char *kEngBuild = "eng";
41*ec779b8eSAndroid Build Coastguard Worker const char *kTestBuild = "test";
42*ec779b8eSAndroid Build Coastguard Worker
43*ec779b8eSAndroid Build Coastguard Worker // @return true if the current build is 'eng' or 'test'.
isTestBuild()44*ec779b8eSAndroid Build Coastguard Worker bool isTestBuild()
45*ec779b8eSAndroid Build Coastguard Worker {
46*ec779b8eSAndroid Build Coastguard Worker char prop[PROPERTY_VALUE_MAX] = { '\0', };
47*ec779b8eSAndroid Build Coastguard Worker
48*ec779b8eSAndroid Build Coastguard Worker property_get(kBuildTypePropName, prop, "\0");
49*ec779b8eSAndroid Build Coastguard Worker return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
50*ec779b8eSAndroid Build Coastguard Worker }
51*ec779b8eSAndroid Build Coastguard Worker
52*ec779b8eSAndroid Build Coastguard Worker // @return true if the url scheme is 'test:'
isTestUrl(const char * url)53*ec779b8eSAndroid Build Coastguard Worker bool isTestUrl(const char *url)
54*ec779b8eSAndroid Build Coastguard Worker {
55*ec779b8eSAndroid Build Coastguard Worker return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
56*ec779b8eSAndroid Build Coastguard Worker }
57*ec779b8eSAndroid Build Coastguard Worker
58*ec779b8eSAndroid Build Coastguard Worker } // anonymous namespace
59*ec779b8eSAndroid Build Coastguard Worker
60*ec779b8eSAndroid Build Coastguard Worker namespace android {
61*ec779b8eSAndroid Build Coastguard Worker
TestPlayerStub()62*ec779b8eSAndroid Build Coastguard Worker TestPlayerStub::TestPlayerStub()
63*ec779b8eSAndroid Build Coastguard Worker :mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
64*ec779b8eSAndroid Build Coastguard Worker mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
65*ec779b8eSAndroid Build Coastguard Worker mPlayer(NULL) { }
66*ec779b8eSAndroid Build Coastguard Worker
~TestPlayerStub()67*ec779b8eSAndroid Build Coastguard Worker TestPlayerStub::~TestPlayerStub()
68*ec779b8eSAndroid Build Coastguard Worker {
69*ec779b8eSAndroid Build Coastguard Worker resetInternal();
70*ec779b8eSAndroid Build Coastguard Worker }
71*ec779b8eSAndroid Build Coastguard Worker
initCheck()72*ec779b8eSAndroid Build Coastguard Worker status_t TestPlayerStub::initCheck()
73*ec779b8eSAndroid Build Coastguard Worker {
74*ec779b8eSAndroid Build Coastguard Worker return isTestBuild() ? OK : INVALID_OPERATION;
75*ec779b8eSAndroid Build Coastguard Worker }
76*ec779b8eSAndroid Build Coastguard Worker
77*ec779b8eSAndroid Build Coastguard Worker // Parse mUrl to get:
78*ec779b8eSAndroid Build Coastguard Worker // * The library to be dlopened.
79*ec779b8eSAndroid Build Coastguard Worker // * The url to be passed to the real setDataSource impl.
80*ec779b8eSAndroid Build Coastguard Worker //
81*ec779b8eSAndroid Build Coastguard Worker // mUrl is expected to be in following format:
82*ec779b8eSAndroid Build Coastguard Worker //
83*ec779b8eSAndroid Build Coastguard Worker // test:<name of the .so>?url=<url for setDataSource>
84*ec779b8eSAndroid Build Coastguard Worker //
85*ec779b8eSAndroid Build Coastguard Worker // The value of the url parameter is treated as a string (no
86*ec779b8eSAndroid Build Coastguard Worker // unescaping of illegal charaters).
parseUrl()87*ec779b8eSAndroid Build Coastguard Worker status_t TestPlayerStub::parseUrl()
88*ec779b8eSAndroid Build Coastguard Worker {
89*ec779b8eSAndroid Build Coastguard Worker if (strlen(mUrl) < strlen(kTestUrlScheme)) {
90*ec779b8eSAndroid Build Coastguard Worker resetInternal();
91*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
92*ec779b8eSAndroid Build Coastguard Worker }
93*ec779b8eSAndroid Build Coastguard Worker
94*ec779b8eSAndroid Build Coastguard Worker char *i = mUrl + strlen(kTestUrlScheme);
95*ec779b8eSAndroid Build Coastguard Worker
96*ec779b8eSAndroid Build Coastguard Worker mFilename = i;
97*ec779b8eSAndroid Build Coastguard Worker
98*ec779b8eSAndroid Build Coastguard Worker while (*i != '\0' && *i != '?') {
99*ec779b8eSAndroid Build Coastguard Worker ++i;
100*ec779b8eSAndroid Build Coastguard Worker }
101*ec779b8eSAndroid Build Coastguard Worker
102*ec779b8eSAndroid Build Coastguard Worker if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
103*ec779b8eSAndroid Build Coastguard Worker resetInternal();
104*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
105*ec779b8eSAndroid Build Coastguard Worker }
106*ec779b8eSAndroid Build Coastguard Worker *i = '\0'; // replace '?' to nul-terminate mFilename
107*ec779b8eSAndroid Build Coastguard Worker
108*ec779b8eSAndroid Build Coastguard Worker mContentUrl = i + 1 + strlen(kUrlParam);
109*ec779b8eSAndroid Build Coastguard Worker return OK;
110*ec779b8eSAndroid Build Coastguard Worker }
111*ec779b8eSAndroid Build Coastguard Worker
112*ec779b8eSAndroid Build Coastguard Worker // Load the dynamic library.
113*ec779b8eSAndroid Build Coastguard Worker // Create the test player.
114*ec779b8eSAndroid Build Coastguard Worker // Call setDataSource on the test player with the url in param.
setDataSource(const sp<IMediaHTTPService> & httpService,const char * url,const KeyedVector<String8,String8> * headers)115*ec779b8eSAndroid Build Coastguard Worker status_t TestPlayerStub::setDataSource(
116*ec779b8eSAndroid Build Coastguard Worker const sp<IMediaHTTPService> &httpService,
117*ec779b8eSAndroid Build Coastguard Worker const char *url,
118*ec779b8eSAndroid Build Coastguard Worker const KeyedVector<String8, String8> *headers) {
119*ec779b8eSAndroid Build Coastguard Worker if (!isTestUrl(url) || NULL != mHandle) {
120*ec779b8eSAndroid Build Coastguard Worker return INVALID_OPERATION;
121*ec779b8eSAndroid Build Coastguard Worker }
122*ec779b8eSAndroid Build Coastguard Worker
123*ec779b8eSAndroid Build Coastguard Worker mUrl = strdup(url);
124*ec779b8eSAndroid Build Coastguard Worker
125*ec779b8eSAndroid Build Coastguard Worker status_t status = parseUrl();
126*ec779b8eSAndroid Build Coastguard Worker
127*ec779b8eSAndroid Build Coastguard Worker if (OK != status) {
128*ec779b8eSAndroid Build Coastguard Worker resetInternal();
129*ec779b8eSAndroid Build Coastguard Worker return status;
130*ec779b8eSAndroid Build Coastguard Worker }
131*ec779b8eSAndroid Build Coastguard Worker
132*ec779b8eSAndroid Build Coastguard Worker ::dlerror(); // Clears any pending error.
133*ec779b8eSAndroid Build Coastguard Worker
134*ec779b8eSAndroid Build Coastguard Worker // Load the test player from the url. dlopen will fail if the lib
135*ec779b8eSAndroid Build Coastguard Worker // is not there. dls are under /system/lib
136*ec779b8eSAndroid Build Coastguard Worker // None of the entry points should be NULL.
137*ec779b8eSAndroid Build Coastguard Worker mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
138*ec779b8eSAndroid Build Coastguard Worker if (!mHandle) {
139*ec779b8eSAndroid Build Coastguard Worker ALOGE("dlopen failed: %s", ::dlerror());
140*ec779b8eSAndroid Build Coastguard Worker resetInternal();
141*ec779b8eSAndroid Build Coastguard Worker return UNKNOWN_ERROR;
142*ec779b8eSAndroid Build Coastguard Worker }
143*ec779b8eSAndroid Build Coastguard Worker
144*ec779b8eSAndroid Build Coastguard Worker // Load the 2 entry points to create and delete instances.
145*ec779b8eSAndroid Build Coastguard Worker const char *err;
146*ec779b8eSAndroid Build Coastguard Worker mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
147*ec779b8eSAndroid Build Coastguard Worker "newPlayer"));
148*ec779b8eSAndroid Build Coastguard Worker err = ::dlerror();
149*ec779b8eSAndroid Build Coastguard Worker if (err || mNewPlayer == NULL) {
150*ec779b8eSAndroid Build Coastguard Worker // if err is NULL the string <null> is inserted in the logs =>
151*ec779b8eSAndroid Build Coastguard Worker // mNewPlayer was NULL.
152*ec779b8eSAndroid Build Coastguard Worker ALOGE("dlsym for newPlayer failed %s", err);
153*ec779b8eSAndroid Build Coastguard Worker resetInternal();
154*ec779b8eSAndroid Build Coastguard Worker return UNKNOWN_ERROR;
155*ec779b8eSAndroid Build Coastguard Worker }
156*ec779b8eSAndroid Build Coastguard Worker
157*ec779b8eSAndroid Build Coastguard Worker mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
158*ec779b8eSAndroid Build Coastguard Worker "deletePlayer"));
159*ec779b8eSAndroid Build Coastguard Worker err = ::dlerror();
160*ec779b8eSAndroid Build Coastguard Worker if (err || mDeletePlayer == NULL) {
161*ec779b8eSAndroid Build Coastguard Worker ALOGE("dlsym for deletePlayer failed %s", err);
162*ec779b8eSAndroid Build Coastguard Worker resetInternal();
163*ec779b8eSAndroid Build Coastguard Worker return UNKNOWN_ERROR;
164*ec779b8eSAndroid Build Coastguard Worker }
165*ec779b8eSAndroid Build Coastguard Worker
166*ec779b8eSAndroid Build Coastguard Worker mPlayer = (*mNewPlayer)();
167*ec779b8eSAndroid Build Coastguard Worker return mPlayer->setDataSource(httpService, mContentUrl, headers);
168*ec779b8eSAndroid Build Coastguard Worker }
169*ec779b8eSAndroid Build Coastguard Worker
170*ec779b8eSAndroid Build Coastguard Worker // Internal cleanup.
resetInternal()171*ec779b8eSAndroid Build Coastguard Worker status_t TestPlayerStub::resetInternal()
172*ec779b8eSAndroid Build Coastguard Worker {
173*ec779b8eSAndroid Build Coastguard Worker if(mUrl) {
174*ec779b8eSAndroid Build Coastguard Worker free(mUrl);
175*ec779b8eSAndroid Build Coastguard Worker mUrl = NULL;
176*ec779b8eSAndroid Build Coastguard Worker }
177*ec779b8eSAndroid Build Coastguard Worker mFilename = NULL;
178*ec779b8eSAndroid Build Coastguard Worker mContentUrl = NULL;
179*ec779b8eSAndroid Build Coastguard Worker
180*ec779b8eSAndroid Build Coastguard Worker if (mPlayer) {
181*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(mDeletePlayer != NULL, "mDeletePlayer is null");
182*ec779b8eSAndroid Build Coastguard Worker (*mDeletePlayer)(mPlayer);
183*ec779b8eSAndroid Build Coastguard Worker mPlayer = NULL;
184*ec779b8eSAndroid Build Coastguard Worker }
185*ec779b8eSAndroid Build Coastguard Worker
186*ec779b8eSAndroid Build Coastguard Worker if (mHandle) {
187*ec779b8eSAndroid Build Coastguard Worker ::dlclose(mHandle);
188*ec779b8eSAndroid Build Coastguard Worker mHandle = NULL;
189*ec779b8eSAndroid Build Coastguard Worker }
190*ec779b8eSAndroid Build Coastguard Worker return OK;
191*ec779b8eSAndroid Build Coastguard Worker }
192*ec779b8eSAndroid Build Coastguard Worker
canBeUsed(const char * url)193*ec779b8eSAndroid Build Coastguard Worker /* static */ bool TestPlayerStub::canBeUsed(const char *url)
194*ec779b8eSAndroid Build Coastguard Worker {
195*ec779b8eSAndroid Build Coastguard Worker return isTestBuild() && isTestUrl(url);
196*ec779b8eSAndroid Build Coastguard Worker }
197*ec779b8eSAndroid Build Coastguard Worker
198*ec779b8eSAndroid Build Coastguard Worker } // namespace android
199