blob: e6f62311ef4e40fbf250339ac16a6bc15038a0d5 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2**
3** Copyright 2008, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18// Proxy for media player implementations
19
20//#define LOG_NDEBUG 0
21#define LOG_TAG "MediaPlayerService"
22#include <utils/Log.h>
23
24#include <sys/types.h>
25#include <sys/stat.h>
Gloria Wangd211f412011-02-19 18:37:57 -080026#include <sys/time.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027#include <dirent.h>
28#include <unistd.h>
29
30#include <string.h>
Mathias Agopiana650aaa2009-06-03 17:32:49 -070031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032#include <cutils/atomic.h>
Nicolas Catania8f5fcab2009-07-13 14:37:49 -070033#include <cutils/properties.h> // for property_get
Mathias Agopiana650aaa2009-06-03 17:32:49 -070034
35#include <utils/misc.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
37#include <android_runtime/ActivityManager.h>
Mathias Agopiana650aaa2009-06-03 17:32:49 -070038
Mathias Agopian07952722009-05-19 19:08:10 -070039#include <binder/IPCThreadState.h>
40#include <binder/IServiceManager.h>
41#include <binder/MemoryHeapBase.h>
42#include <binder/MemoryBase.h>
Nicolas Catania20cb94e2009-05-12 23:25:55 -070043#include <utils/Errors.h> // for status_t
44#include <utils/String8.h>
Marco Nelissenc39d2e32009-09-20 10:42:13 -070045#include <utils/SystemClock.h>
Nicolas Catania20cb94e2009-05-12 23:25:55 -070046#include <utils/Vector.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047#include <cutils/properties.h>
48
49#include <media/MediaPlayerInterface.h>
50#include <media/mediarecorder.h>
51#include <media/MediaMetadataRetrieverInterface.h>
nikobc726922009-07-20 15:07:26 -070052#include <media/Metadata.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053#include <media/AudioTrack.h>
James Donged732462011-03-14 17:01:38 -070054#include <media/MemoryLeakTrackUtil.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
Dima Zavin34bb4192011-05-11 14:15:23 -070056#include <system/audio.h>
Dima Zavin24fc2fb2011-04-19 22:30:36 -070057
Gloria Wangd211f412011-02-19 18:37:57 -080058#include <private/android_filesystem_config.h>
59
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060#include "MediaRecorderClient.h"
61#include "MediaPlayerService.h"
62#include "MetadataRetrieverClient.h"
63
64#include "MidiFile.h"
Nicolas Catania8f5fcab2009-07-13 14:37:49 -070065#include "TestPlayerStub.h"
Andreas Hubere46b7be2009-07-14 16:56:47 -070066#include "StagefrightPlayer.h"
Andreas Hubera1587462010-12-15 15:17:42 -080067#include "nuplayer/NuPlayerDriver.h"
Andreas Hubere46b7be2009-07-14 16:56:47 -070068
Andreas Hubere46b7be2009-07-14 16:56:47 -070069#include <OMX.h>
Nicolas Catania8f5fcab2009-07-13 14:37:49 -070070
Mike J. Chenda548442011-08-15 13:24:13 -070071namespace android {
72sp<MediaPlayerBase> createAAH_TXPlayer();
73sp<MediaPlayerBase> createAAH_RXPlayer();
74}
75
Nicolas Cataniab2c69392009-07-08 08:57:42 -070076namespace {
nikobc726922009-07-20 15:07:26 -070077using android::media::Metadata;
Nicolas Cataniab2c69392009-07-08 08:57:42 -070078using android::status_t;
79using android::OK;
80using android::BAD_VALUE;
81using android::NOT_ENOUGH_DATA;
82using android::Parcel;
Nicolas Cataniab2c69392009-07-08 08:57:42 -070083
84// Max number of entries in the filter.
85const int kMaxFilterSize = 64; // I pulled that out of thin air.
86
nikobc726922009-07-20 15:07:26 -070087// FIXME: Move all the metadata related function in the Metadata.cpp
niko89948372009-07-16 16:39:53 -070088
Nicolas Cataniab2c69392009-07-08 08:57:42 -070089
90// Unmarshall a filter from a Parcel.
91// Filter format in a parcel:
92//
93// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
94// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95// | number of entries (n) |
96// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97// | metadata type 1 |
98// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99// | metadata type 2 |
100// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101// ....
102// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103// | metadata type n |
104// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105//
106// @param p Parcel that should start with a filter.
107// @param[out] filter On exit contains the list of metadata type to be
108// filtered.
109// @param[out] status On exit contains the status code to be returned.
110// @return true if the parcel starts with a valid filter.
111bool unmarshallFilter(const Parcel& p,
nikobc726922009-07-20 15:07:26 -0700112 Metadata::Filter *filter,
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700113 status_t *status)
114{
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700115 int32_t val;
116 if (p.readInt32(&val) != OK)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700117 {
118 LOGE("Failed to read filter's length");
119 *status = NOT_ENOUGH_DATA;
120 return false;
121 }
122
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700123 if( val > kMaxFilterSize || val < 0)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700124 {
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700125 LOGE("Invalid filter len %d", val);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700126 *status = BAD_VALUE;
127 return false;
128 }
129
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700130 const size_t num = val;
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700131
132 filter->clear();
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700133 filter->setCapacity(num);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700134
nikobc726922009-07-20 15:07:26 -0700135 size_t size = num * sizeof(Metadata::Type);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700136
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700137
138 if (p.dataAvail() < size)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700139 {
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700140 LOGE("Filter too short expected %d but got %d", size, p.dataAvail());
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700141 *status = NOT_ENOUGH_DATA;
142 return false;
143 }
144
nikobc726922009-07-20 15:07:26 -0700145 const Metadata::Type *data =
146 static_cast<const Metadata::Type*>(p.readInplace(size));
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700147
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700148 if (NULL == data)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700149 {
150 LOGE("Filter had no data");
151 *status = BAD_VALUE;
152 return false;
153 }
154
155 // TODO: The stl impl of vector would be more efficient here
156 // because it degenerates into a memcpy on pod types. Try to
157 // replace later or use stl::set.
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700158 for (size_t i = 0; i < num; ++i)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700159 {
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700160 filter->add(*data);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700161 ++data;
162 }
163 *status = OK;
164 return true;
165}
166
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700167// @param filter Of metadata type.
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700168// @param val To be searched.
169// @return true if a match was found.
nikobc726922009-07-20 15:07:26 -0700170bool findMetadata(const Metadata::Filter& filter, const int32_t val)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700171{
172 // Deal with empty and ANY right away
173 if (filter.isEmpty()) return false;
nikobc726922009-07-20 15:07:26 -0700174 if (filter[0] == Metadata::kAny) return true;
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700175
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700176 return filter.indexOf(val) >= 0;
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700177}
178
179} // anonymous namespace
180
181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182namespace android {
183
184// TODO: Temp hack until we can register players
185typedef struct {
186 const char *extension;
187 const player_type playertype;
188} extmap;
189extmap FILE_EXTS [] = {
190 {".mid", SONIVOX_PLAYER},
191 {".midi", SONIVOX_PLAYER},
192 {".smf", SONIVOX_PLAYER},
193 {".xmf", SONIVOX_PLAYER},
194 {".imy", SONIVOX_PLAYER},
195 {".rtttl", SONIVOX_PLAYER},
196 {".rtx", SONIVOX_PLAYER},
197 {".ota", SONIVOX_PLAYER},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198};
199
200// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
202/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
203
204void MediaPlayerService::instantiate() {
205 defaultServiceManager()->addService(
206 String16("media.player"), new MediaPlayerService());
207}
208
209MediaPlayerService::MediaPlayerService()
210{
211 LOGV("MediaPlayerService created");
212 mNextConnId = 1;
Gloria Wang9b3f1522011-02-24 14:51:45 -0800213
214 mBatteryAudio.refCount = 0;
215 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
216 mBatteryAudio.deviceOn[i] = 0;
217 mBatteryAudio.lastTime[i] = 0;
218 mBatteryAudio.totalTime[i] = 0;
219 }
220 // speaker is on by default
221 mBatteryAudio.deviceOn[SPEAKER] = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222}
223
224MediaPlayerService::~MediaPlayerService()
225{
226 LOGV("MediaPlayerService destroyed");
227}
228
229sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
230{
Gloria Wang608a2632009-10-29 15:46:37 -0700231 sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid);
232 wp<MediaRecorderClient> w = recorder;
233 Mutex::Autolock lock(mLock);
234 mMediaRecorderClients.add(w);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 LOGV("Create new media recorder client from pid %d", pid);
236 return recorder;
237}
238
Gloria Wang608a2632009-10-29 15:46:37 -0700239void MediaPlayerService::removeMediaRecorderClient(wp<MediaRecorderClient> client)
240{
241 Mutex::Autolock lock(mLock);
242 mMediaRecorderClients.remove(client);
243 LOGV("Delete media recorder client");
244}
245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pid)
247{
248 sp<MetadataRetrieverClient> retriever = new MetadataRetrieverClient(pid);
249 LOGV("Create new media retriever from pid %d", pid);
250 return retriever;
251}
252
Andreas Huber25643002010-01-28 11:19:57 -0800253sp<IMediaPlayer> MediaPlayerService::create(
254 pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
Eric Laurent619346f2010-06-21 09:27:30 -0700255 const KeyedVector<String8, String8> *headers, int audioSessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256{
257 int32_t connId = android_atomic_inc(&mNextConnId);
Andreas Huber603d7392011-06-30 15:47:02 -0700258
259 sp<Client> c = new Client(
260 this, pid, connId, client, audioSessionId,
261 IPCThreadState::self()->getCallingUid());
262
Ashish Sharmad5a20d82011-07-07 17:57:05 -0700263 LOGV("Create new client(%d) from pid %d, uid %d, url=%s, connId=%d, audioSessionId=%d",
264 connId, pid, IPCThreadState::self()->getCallingUid(), url, connId, audioSessionId);
Andreas Huber25643002010-01-28 11:19:57 -0800265 if (NO_ERROR != c->setDataSource(url, headers))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 {
267 c.clear();
268 return c;
269 }
270 wp<Client> w = c;
271 Mutex::Autolock lock(mLock);
272 mClients.add(w);
273 return c;
274}
275
276sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,
Eric Laurent619346f2010-06-21 09:27:30 -0700277 int fd, int64_t offset, int64_t length, int audioSessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278{
279 int32_t connId = android_atomic_inc(&mNextConnId);
Andreas Huber603d7392011-06-30 15:47:02 -0700280
281 sp<Client> c = new Client(
282 this, pid, connId, client, audioSessionId,
283 IPCThreadState::self()->getCallingUid());
284
Ashish Sharmad5a20d82011-07-07 17:57:05 -0700285 LOGV("Create new client(%d) from pid %d, uid %d, fd=%d, offset=%lld, "
286 "length=%lld, audioSessionId=%d", connId, pid,
287 IPCThreadState::self()->getCallingUid(), fd, offset, length, audioSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 if (NO_ERROR != c->setDataSource(fd, offset, length)) {
289 c.clear();
290 } else {
291 wp<Client> w = c;
292 Mutex::Autolock lock(mLock);
293 mClients.add(w);
294 }
295 ::close(fd);
296 return c;
297}
298
Andreas Huber52b52cd2010-11-23 11:41:34 -0800299sp<IMediaPlayer> MediaPlayerService::create(
300 pid_t pid, const sp<IMediaPlayerClient> &client,
301 const sp<IStreamSource> &source, int audioSessionId) {
302 int32_t connId = android_atomic_inc(&mNextConnId);
Andreas Huber603d7392011-06-30 15:47:02 -0700303
304 sp<Client> c = new Client(
305 this, pid, connId, client, audioSessionId,
306 IPCThreadState::self()->getCallingUid());
Andreas Huber52b52cd2010-11-23 11:41:34 -0800307
308 LOGV("Create new client(%d) from pid %d, audioSessionId=%d",
309 connId, pid, audioSessionId);
310
311 if (OK != c->setDataSource(source)) {
312 c.clear();
313 } else {
314 wp<Client> w = c;
315 Mutex::Autolock lock(mLock);
316 mClients.add(w);
317 }
318
319 return c;
320}
321
Andreas Huber784202e2009-10-15 13:46:54 -0700322sp<IOMX> MediaPlayerService::getOMX() {
323 Mutex::Autolock autoLock(mLock);
324
325 if (mOMX.get() == NULL) {
326 mOMX = new OMX;
327 }
328
329 return mOMX;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700330}
331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
333{
334 const size_t SIZE = 256;
335 char buffer[SIZE];
336 String8 result;
337
338 result.append(" AudioCache\n");
339 if (mHeap != 0) {
340 snprintf(buffer, 255, " heap base(%p), size(%d), flags(%d), device(%s)\n",
341 mHeap->getBase(), mHeap->getSize(), mHeap->getFlags(), mHeap->getDevice());
342 result.append(buffer);
343 }
344 snprintf(buffer, 255, " msec per frame(%f), channel count(%d), format(%d), frame count(%ld)\n",
345 mMsecsPerFrame, mChannelCount, mFormat, mFrameCount);
346 result.append(buffer);
347 snprintf(buffer, 255, " sample rate(%d), size(%d), error(%d), command complete(%s)\n",
348 mSampleRate, mSize, mError, mCommandComplete?"true":"false");
349 result.append(buffer);
350 ::write(fd, result.string(), result.size());
351 return NO_ERROR;
352}
353
354status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& args) const
355{
356 const size_t SIZE = 256;
357 char buffer[SIZE];
358 String8 result;
359
360 result.append(" AudioOutput\n");
361 snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
362 mStreamType, mLeftVolume, mRightVolume);
363 result.append(buffer);
364 snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
365 mMsecsPerFrame, mLatency);
366 result.append(buffer);
Eric Laurent7070b362010-07-16 07:43:46 -0700367 snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
368 mAuxEffectId, mSendLevel);
369 result.append(buffer);
370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 ::write(fd, result.string(), result.size());
372 if (mTrack != 0) {
373 mTrack->dump(fd, args);
374 }
375 return NO_ERROR;
376}
377
378status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args) const
379{
380 const size_t SIZE = 256;
381 char buffer[SIZE];
382 String8 result;
383 result.append(" Client\n");
384 snprintf(buffer, 255, " pid(%d), connId(%d), status(%d), looping(%s)\n",
385 mPid, mConnId, mStatus, mLoop?"true": "false");
386 result.append(buffer);
387 write(fd, result.string(), result.size());
Andreas Huberfddf5d92011-06-07 15:52:25 -0700388 if (mPlayer != NULL) {
389 mPlayer->dump(fd, args);
390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 if (mAudioOutput != 0) {
392 mAudioOutput->dump(fd, args);
393 }
394 write(fd, "\n", 1);
395 return NO_ERROR;
396}
397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
399{
400 const size_t SIZE = 256;
401 char buffer[SIZE];
402 String8 result;
403 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
404 snprintf(buffer, SIZE, "Permission Denial: "
405 "can't dump MediaPlayerService from pid=%d, uid=%d\n",
406 IPCThreadState::self()->getCallingPid(),
407 IPCThreadState::self()->getCallingUid());
408 result.append(buffer);
409 } else {
410 Mutex::Autolock lock(mLock);
411 for (int i = 0, n = mClients.size(); i < n; ++i) {
412 sp<Client> c = mClients[i].promote();
413 if (c != 0) c->dump(fd, args);
414 }
James Dong929642e2010-07-08 11:16:11 -0700415 if (mMediaRecorderClients.size() == 0) {
416 result.append(" No media recorder client\n\n");
417 } else {
418 for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
419 sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
420 snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
421 result.append(buffer);
422 write(fd, result.string(), result.size());
423 result = "\n";
424 c->dump(fd, args);
425 }
Gloria Wang608a2632009-10-29 15:46:37 -0700426 }
427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 result.append(" Files opened and/or mapped:\n");
Glenn Kasten6af763b2011-05-04 17:58:57 -0700429 snprintf(buffer, SIZE, "/proc/%d/maps", gettid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 FILE *f = fopen(buffer, "r");
431 if (f) {
432 while (!feof(f)) {
433 fgets(buffer, SIZE, f);
Dave Sparks124a3462010-09-27 16:55:18 -0700434 if (strstr(buffer, " /mnt/sdcard/") ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 strstr(buffer, " /system/sounds/") ||
Dave Sparks124a3462010-09-27 16:55:18 -0700436 strstr(buffer, " /data/") ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 strstr(buffer, " /system/media/")) {
438 result.append(" ");
439 result.append(buffer);
440 }
441 }
442 fclose(f);
443 } else {
444 result.append("couldn't open ");
445 result.append(buffer);
446 result.append("\n");
447 }
448
Glenn Kasten6af763b2011-05-04 17:58:57 -0700449 snprintf(buffer, SIZE, "/proc/%d/fd", gettid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 DIR *d = opendir(buffer);
451 if (d) {
452 struct dirent *ent;
453 while((ent = readdir(d)) != NULL) {
454 if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
Glenn Kasten6af763b2011-05-04 17:58:57 -0700455 snprintf(buffer, SIZE, "/proc/%d/fd/%s", gettid(), ent->d_name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 struct stat s;
457 if (lstat(buffer, &s) == 0) {
458 if ((s.st_mode & S_IFMT) == S_IFLNK) {
459 char linkto[256];
460 int len = readlink(buffer, linkto, sizeof(linkto));
461 if(len > 0) {
462 if(len > 255) {
463 linkto[252] = '.';
464 linkto[253] = '.';
465 linkto[254] = '.';
466 linkto[255] = 0;
467 } else {
468 linkto[len] = 0;
469 }
Dave Sparks124a3462010-09-27 16:55:18 -0700470 if (strstr(linkto, "/mnt/sdcard/") == linkto ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 strstr(linkto, "/system/sounds/") == linkto ||
Dave Sparks124a3462010-09-27 16:55:18 -0700472 strstr(linkto, "/data/") == linkto ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 strstr(linkto, "/system/media/") == linkto) {
474 result.append(" ");
475 result.append(buffer);
476 result.append(" -> ");
477 result.append(linkto);
478 result.append("\n");
479 }
480 }
481 } else {
482 result.append(" unexpected type for ");
483 result.append(buffer);
484 result.append("\n");
485 }
486 }
487 }
488 }
489 closedir(d);
490 } else {
491 result.append("couldn't open ");
492 result.append(buffer);
493 result.append("\n");
494 }
495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 bool dumpMem = false;
497 for (size_t i = 0; i < args.size(); i++) {
498 if (args[i] == String16("-m")) {
499 dumpMem = true;
500 }
501 }
502 if (dumpMem) {
James Donged732462011-03-14 17:01:38 -0700503 dumpMemoryAddresses(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 }
506 write(fd, result.string(), result.size());
507 return NO_ERROR;
508}
509
510void MediaPlayerService::removeClient(wp<Client> client)
511{
512 Mutex::Autolock lock(mLock);
513 mClients.remove(client);
514}
515
Andreas Huber603d7392011-06-30 15:47:02 -0700516MediaPlayerService::Client::Client(
517 const sp<MediaPlayerService>& service, pid_t pid,
518 int32_t connId, const sp<IMediaPlayerClient>& client,
519 int audioSessionId, uid_t uid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520{
521 LOGV("Client(%d) constructor", connId);
522 mPid = pid;
523 mConnId = connId;
524 mService = service;
525 mClient = client;
526 mLoop = false;
527 mStatus = NO_INIT;
Eric Laurent619346f2010-06-21 09:27:30 -0700528 mAudioSessionId = audioSessionId;
Andreas Huber603d7392011-06-30 15:47:02 -0700529 mUID = uid;
Eric Laurent619346f2010-06-21 09:27:30 -0700530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531#if CALLBACK_ANTAGONIZER
532 LOGD("create Antagonizer");
533 mAntagonizer = new Antagonizer(notify, this);
534#endif
535}
536
537MediaPlayerService::Client::~Client()
538{
539 LOGV("Client(%d) destructor pid = %d", mConnId, mPid);
540 mAudioOutput.clear();
541 wp<Client> client(this);
542 disconnect();
543 mService->removeClient(client);
544}
545
546void MediaPlayerService::Client::disconnect()
547{
548 LOGV("disconnect(%d) from pid %d", mConnId, mPid);
549 // grab local reference and clear main reference to prevent future
550 // access to object
551 sp<MediaPlayerBase> p;
552 {
553 Mutex::Autolock l(mLock);
554 p = mPlayer;
555 }
Dave Sparkscb9a44e2009-03-24 17:57:12 -0700556 mClient.clear();
Andreas Hubere46b7be2009-07-14 16:56:47 -0700557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 mPlayer.clear();
559
560 // clear the notification to prevent callbacks to dead client
561 // and reset the player. We assume the player will serialize
562 // access to itself if necessary.
563 if (p != 0) {
564 p->setNotifyCallback(0, 0);
565#if CALLBACK_ANTAGONIZER
566 LOGD("kill Antagonizer");
567 mAntagonizer->kill();
568#endif
569 p->reset();
570 }
571
572 IPCThreadState::self()->flushCommands();
573}
574
Andreas Huber0d596d42009-08-07 09:30:32 -0700575static player_type getDefaultPlayerType() {
Andreas Huber8d65dd22010-06-23 16:40:57 -0700576 return STAGEFRIGHT_PLAYER;
Andreas Huber0d596d42009-08-07 09:30:32 -0700577}
578
James Dong392ff3b2009-09-06 14:29:45 -0700579player_type getPlayerType(int fd, int64_t offset, int64_t length)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580{
581 char buf[20];
582 lseek(fd, offset, SEEK_SET);
583 read(fd, buf, sizeof(buf));
584 lseek(fd, offset, SEEK_SET);
585
586 long ident = *((long*)buf);
587
588 // Ogg vorbis?
589 if (ident == 0x5367674f) // 'OggS'
Andreas Huber8d65dd22010-06-23 16:40:57 -0700590 return STAGEFRIGHT_PLAYER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591
592 // Some kind of MIDI?
593 EAS_DATA_HANDLE easdata;
594 if (EAS_Init(&easdata) == EAS_SUCCESS) {
595 EAS_FILE locator;
596 locator.path = NULL;
597 locator.fd = fd;
598 locator.offset = offset;
599 locator.length = length;
600 EAS_HANDLE eashandle;
601 if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
602 EAS_CloseFile(easdata, eashandle);
603 EAS_Shutdown(easdata);
604 return SONIVOX_PLAYER;
605 }
606 EAS_Shutdown(easdata);
607 }
608
Andreas Huber0d596d42009-08-07 09:30:32 -0700609 return getDefaultPlayerType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610}
611
James Dong392ff3b2009-09-06 14:29:45 -0700612player_type getPlayerType(const char* url)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613{
Nicolas Catania8f5fcab2009-07-13 14:37:49 -0700614 if (TestPlayerStub::canBeUsed(url)) {
615 return TEST_PLAYER;
616 }
617
Andreas Huber554d0ea2011-03-21 16:28:04 -0700618 if (!strncasecmp("http://", url, 7)
619 || !strncasecmp("https://", url, 8)) {
Andreas Huberd6c421f2011-02-16 09:05:38 -0800620 size_t len = strlen(url);
621 if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
622 return NU_PLAYER;
623 }
Andreas Huber54e66492010-12-23 10:27:40 -0800624
Andreas Huberd6c421f2011-02-16 09:05:38 -0800625 if (strstr(url,"m3u8")) {
626 return NU_PLAYER;
Andreas Huber54e66492010-12-23 10:27:40 -0800627 }
628 }
629
Mike J. Chenda548442011-08-15 13:24:13 -0700630 if (!strncasecmp("aahRX://", url, 8)) {
631 return AAH_RX_PLAYER;
632 }
633
634 if (!strncasecmp("aahTX://", url, 8)) {
635 return AAH_TX_PLAYER;
636 }
637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 // use MidiFile for MIDI extensions
639 int lenURL = strlen(url);
640 for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
641 int len = strlen(FILE_EXTS[i].extension);
642 int start = lenURL - len;
643 if (start > 0) {
Atsushi Enoebcc51d2010-03-19 23:18:02 +0900644 if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) {
Andreas Huber8d65dd22010-06-23 16:40:57 -0700645 return FILE_EXTS[i].playertype;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 }
647 }
648 }
649
Andreas Huber0d596d42009-08-07 09:30:32 -0700650 return getDefaultPlayerType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651}
652
653static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
654 notify_callback_f notifyFunc)
655{
656 sp<MediaPlayerBase> p;
657 switch (playerType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 case SONIVOX_PLAYER:
659 LOGV(" create MidiFile");
660 p = new MidiFile();
661 break;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700662 case STAGEFRIGHT_PLAYER:
663 LOGV(" create StagefrightPlayer");
664 p = new StagefrightPlayer;
665 break;
Andreas Hubera1587462010-12-15 15:17:42 -0800666 case NU_PLAYER:
667 LOGV(" create NuPlayer");
668 p = new NuPlayerDriver;
669 break;
Nicolas Catania8f5fcab2009-07-13 14:37:49 -0700670 case TEST_PLAYER:
671 LOGV("Create Test Player stub");
672 p = new TestPlayerStub();
673 break;
Mike J. Chenda548442011-08-15 13:24:13 -0700674 case AAH_RX_PLAYER:
675 LOGV(" create A@H RX Player");
676 p = createAAH_RXPlayer();
677 break;
678 case AAH_TX_PLAYER:
679 LOGV(" create A@H TX Player");
680 p = createAAH_TXPlayer();
681 break;
James Dong8ec2d9a2010-11-10 18:42:40 -0800682 default:
683 LOGE("Unknown player type: %d", playerType);
684 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 }
686 if (p != NULL) {
687 if (p->initCheck() == NO_ERROR) {
688 p->setNotifyCallback(cookie, notifyFunc);
689 } else {
690 p.clear();
691 }
692 }
693 if (p == NULL) {
694 LOGE("Failed to create player object");
695 }
696 return p;
697}
698
699sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
700{
701 // determine if we have the right player type
702 sp<MediaPlayerBase> p = mPlayer;
703 if ((p != NULL) && (p->playerType() != playerType)) {
704 LOGV("delete player");
705 p.clear();
706 }
707 if (p == NULL) {
708 p = android::createPlayer(playerType, this, notify);
709 }
Andreas Huber603d7392011-06-30 15:47:02 -0700710
Jason Simmonsd9792ac2011-08-12 13:46:55 -0700711 if (p != NULL) {
712 p->setUID(mUID);
713 }
Andreas Huber603d7392011-06-30 15:47:02 -0700714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 return p;
716}
717
Andreas Huber25643002010-01-28 11:19:57 -0800718status_t MediaPlayerService::Client::setDataSource(
719 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720{
721 LOGV("setDataSource(%s)", url);
722 if (url == NULL)
723 return UNKNOWN_ERROR;
724
725 if (strncmp(url, "content://", 10) == 0) {
726 // get a filedescriptor for the content Uri and
727 // pass it to the setDataSource(fd) method
728
729 String16 url16(url);
730 int fd = android::openContentProviderFile(url16);
731 if (fd < 0)
732 {
733 LOGE("Couldn't open fd for %s", url);
734 return UNKNOWN_ERROR;
735 }
736 setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
737 close(fd);
738 return mStatus;
739 } else {
740 player_type playerType = getPlayerType(url);
741 LOGV("player type = %d", playerType);
742
743 // create the right type of player
744 sp<MediaPlayerBase> p = createPlayer(playerType);
745 if (p == NULL) return NO_INIT;
746
747 if (!p->hardwareOutput()) {
Eric Laurent619346f2010-06-21 09:27:30 -0700748 mAudioOutput = new AudioOutput(mAudioSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
750 }
751
752 // now set data source
753 LOGV(" setDataSource");
Andreas Huber25643002010-01-28 11:19:57 -0800754 mStatus = p->setDataSource(url, headers);
Nicolas Catania8f5fcab2009-07-13 14:37:49 -0700755 if (mStatus == NO_ERROR) {
756 mPlayer = p;
757 } else {
758 LOGE(" error: %d", mStatus);
759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 return mStatus;
761 }
762}
763
764status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
765{
766 LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
767 struct stat sb;
768 int ret = fstat(fd, &sb);
769 if (ret != 0) {
770 LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
771 return UNKNOWN_ERROR;
772 }
773
774 LOGV("st_dev = %llu", sb.st_dev);
775 LOGV("st_mode = %u", sb.st_mode);
776 LOGV("st_uid = %lu", sb.st_uid);
777 LOGV("st_gid = %lu", sb.st_gid);
778 LOGV("st_size = %llu", sb.st_size);
779
780 if (offset >= sb.st_size) {
781 LOGE("offset error");
782 ::close(fd);
783 return UNKNOWN_ERROR;
784 }
785 if (offset + length > sb.st_size) {
786 length = sb.st_size - offset;
787 LOGV("calculated length = %lld", length);
788 }
789
790 player_type playerType = getPlayerType(fd, offset, length);
791 LOGV("player type = %d", playerType);
792
793 // create the right type of player
794 sp<MediaPlayerBase> p = createPlayer(playerType);
795 if (p == NULL) return NO_INIT;
796
797 if (!p->hardwareOutput()) {
Eric Laurent619346f2010-06-21 09:27:30 -0700798 mAudioOutput = new AudioOutput(mAudioSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
800 }
801
802 // now set data source
803 mStatus = p->setDataSource(fd, offset, length);
804 if (mStatus == NO_ERROR) mPlayer = p;
805 return mStatus;
806}
807
Andreas Huber52b52cd2010-11-23 11:41:34 -0800808status_t MediaPlayerService::Client::setDataSource(
809 const sp<IStreamSource> &source) {
810 // create the right type of player
Andreas Hubera1587462010-12-15 15:17:42 -0800811 sp<MediaPlayerBase> p = createPlayer(NU_PLAYER);
Andreas Huber52b52cd2010-11-23 11:41:34 -0800812
813 if (p == NULL) {
814 return NO_INIT;
815 }
816
817 if (!p->hardwareOutput()) {
818 mAudioOutput = new AudioOutput(mAudioSessionId);
819 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
820 }
821
822 // now set data source
823 mStatus = p->setDataSource(source);
824
825 if (mStatus == OK) {
826 mPlayer = p;
827 }
828
829 return mStatus;
830}
831
Andreas Hubere3c01832010-08-16 08:49:37 -0700832status_t MediaPlayerService::Client::setVideoSurface(const sp<Surface>& surface)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833{
834 LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get());
835 sp<MediaPlayerBase> p = getPlayer();
836 if (p == 0) return UNKNOWN_ERROR;
837 return p->setVideoSurface(surface);
838}
839
Glenn Kastencc562a32011-02-08 17:26:17 -0800840status_t MediaPlayerService::Client::setVideoSurfaceTexture(
841 const sp<ISurfaceTexture>& surfaceTexture)
842{
843 LOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, surfaceTexture.get());
844 sp<MediaPlayerBase> p = getPlayer();
845 if (p == 0) return UNKNOWN_ERROR;
846 return p->setVideoSurfaceTexture(surfaceTexture);
847}
848
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700849status_t MediaPlayerService::Client::invoke(const Parcel& request,
850 Parcel *reply)
851{
852 sp<MediaPlayerBase> p = getPlayer();
853 if (p == NULL) return UNKNOWN_ERROR;
854 return p->invoke(request, reply);
855}
856
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700857// This call doesn't need to access the native player.
858status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
859{
860 status_t status;
nikobc726922009-07-20 15:07:26 -0700861 media::Metadata::Filter allow, drop;
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700862
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700863 if (unmarshallFilter(filter, &allow, &status) &&
864 unmarshallFilter(filter, &drop, &status)) {
865 Mutex::Autolock lock(mLock);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700866
867 mMetadataAllow = allow;
868 mMetadataDrop = drop;
869 }
870 return status;
871}
872
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700873status_t MediaPlayerService::Client::getMetadata(
874 bool update_only, bool apply_filter, Parcel *reply)
Nicolas Catania5d55c712009-07-09 09:21:33 -0700875{
nikobc726922009-07-20 15:07:26 -0700876 sp<MediaPlayerBase> player = getPlayer();
877 if (player == 0) return UNKNOWN_ERROR;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700878
niko89948372009-07-16 16:39:53 -0700879 status_t status;
880 // Placeholder for the return code, updated by the caller.
881 reply->writeInt32(-1);
882
nikobc726922009-07-20 15:07:26 -0700883 media::Metadata::Filter ids;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700884
885 // We don't block notifications while we fetch the data. We clear
886 // mMetadataUpdated first so we don't lose notifications happening
887 // during the rest of this call.
888 {
889 Mutex::Autolock lock(mLock);
890 if (update_only) {
niko89948372009-07-16 16:39:53 -0700891 ids = mMetadataUpdated;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700892 }
893 mMetadataUpdated.clear();
894 }
Nicolas Catania5d55c712009-07-09 09:21:33 -0700895
nikobc726922009-07-20 15:07:26 -0700896 media::Metadata metadata(reply);
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700897
nikobc726922009-07-20 15:07:26 -0700898 metadata.appendHeader();
899 status = player->getMetadata(ids, reply);
niko89948372009-07-16 16:39:53 -0700900
901 if (status != OK) {
nikobc726922009-07-20 15:07:26 -0700902 metadata.resetParcel();
niko89948372009-07-16 16:39:53 -0700903 LOGE("getMetadata failed %d", status);
904 return status;
905 }
906
907 // FIXME: Implement filtering on the result. Not critical since
908 // filtering takes place on the update notifications already. This
909 // would be when all the metadata are fetch and a filter is set.
910
niko89948372009-07-16 16:39:53 -0700911 // Everything is fine, update the metadata length.
nikobc726922009-07-20 15:07:26 -0700912 metadata.updateLength();
niko89948372009-07-16 16:39:53 -0700913 return OK;
Nicolas Catania5d55c712009-07-09 09:21:33 -0700914}
915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916status_t MediaPlayerService::Client::prepareAsync()
917{
918 LOGV("[%d] prepareAsync", mConnId);
919 sp<MediaPlayerBase> p = getPlayer();
920 if (p == 0) return UNKNOWN_ERROR;
921 status_t ret = p->prepareAsync();
922#if CALLBACK_ANTAGONIZER
923 LOGD("start Antagonizer");
924 if (ret == NO_ERROR) mAntagonizer->start();
925#endif
926 return ret;
927}
928
929status_t MediaPlayerService::Client::start()
930{
931 LOGV("[%d] start", mConnId);
932 sp<MediaPlayerBase> p = getPlayer();
933 if (p == 0) return UNKNOWN_ERROR;
934 p->setLooping(mLoop);
935 return p->start();
936}
937
938status_t MediaPlayerService::Client::stop()
939{
940 LOGV("[%d] stop", mConnId);
941 sp<MediaPlayerBase> p = getPlayer();
942 if (p == 0) return UNKNOWN_ERROR;
943 return p->stop();
944}
945
946status_t MediaPlayerService::Client::pause()
947{
948 LOGV("[%d] pause", mConnId);
949 sp<MediaPlayerBase> p = getPlayer();
950 if (p == 0) return UNKNOWN_ERROR;
951 return p->pause();
952}
953
954status_t MediaPlayerService::Client::isPlaying(bool* state)
955{
956 *state = false;
957 sp<MediaPlayerBase> p = getPlayer();
958 if (p == 0) return UNKNOWN_ERROR;
959 *state = p->isPlaying();
960 LOGV("[%d] isPlaying: %d", mConnId, *state);
961 return NO_ERROR;
962}
963
964status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
965{
966 LOGV("getCurrentPosition");
967 sp<MediaPlayerBase> p = getPlayer();
968 if (p == 0) return UNKNOWN_ERROR;
969 status_t ret = p->getCurrentPosition(msec);
970 if (ret == NO_ERROR) {
971 LOGV("[%d] getCurrentPosition = %d", mConnId, *msec);
972 } else {
973 LOGE("getCurrentPosition returned %d", ret);
974 }
975 return ret;
976}
977
978status_t MediaPlayerService::Client::getDuration(int *msec)
979{
980 LOGV("getDuration");
981 sp<MediaPlayerBase> p = getPlayer();
982 if (p == 0) return UNKNOWN_ERROR;
983 status_t ret = p->getDuration(msec);
984 if (ret == NO_ERROR) {
985 LOGV("[%d] getDuration = %d", mConnId, *msec);
986 } else {
987 LOGE("getDuration returned %d", ret);
988 }
989 return ret;
990}
991
992status_t MediaPlayerService::Client::seekTo(int msec)
993{
994 LOGV("[%d] seekTo(%d)", mConnId, msec);
995 sp<MediaPlayerBase> p = getPlayer();
996 if (p == 0) return UNKNOWN_ERROR;
997 return p->seekTo(msec);
998}
999
1000status_t MediaPlayerService::Client::reset()
1001{
1002 LOGV("[%d] reset", mConnId);
1003 sp<MediaPlayerBase> p = getPlayer();
1004 if (p == 0) return UNKNOWN_ERROR;
1005 return p->reset();
1006}
1007
1008status_t MediaPlayerService::Client::setAudioStreamType(int type)
1009{
1010 LOGV("[%d] setAudioStreamType(%d)", mConnId, type);
1011 // TODO: for hardware output, call player instead
1012 Mutex::Autolock l(mLock);
1013 if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
1014 return NO_ERROR;
1015}
1016
1017status_t MediaPlayerService::Client::setLooping(int loop)
1018{
1019 LOGV("[%d] setLooping(%d)", mConnId, loop);
1020 mLoop = loop;
1021 sp<MediaPlayerBase> p = getPlayer();
1022 if (p != 0) return p->setLooping(loop);
1023 return NO_ERROR;
1024}
1025
1026status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
1027{
1028 LOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
Mike J. Chenda548442011-08-15 13:24:13 -07001029
1030 // for hardware output, call player instead
1031 sp<MediaPlayerBase> p = getPlayer();
1032 {
1033 Mutex::Autolock l(mLock);
1034 if (p != 0 && p->hardwareOutput()) {
1035 MediaPlayerHWInterface* hwp =
1036 reinterpret_cast<MediaPlayerHWInterface*>(p.get());
1037 return hwp->setVolume(leftVolume, rightVolume);
1038 } else {
1039 if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
1040 return NO_ERROR;
1041 }
1042 }
1043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 return NO_ERROR;
1045}
1046
Eric Laurent7070b362010-07-16 07:43:46 -07001047status_t MediaPlayerService::Client::setAuxEffectSendLevel(float level)
1048{
1049 LOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
1050 Mutex::Autolock l(mLock);
1051 if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
1052 return NO_ERROR;
1053}
1054
1055status_t MediaPlayerService::Client::attachAuxEffect(int effectId)
1056{
1057 LOGV("[%d] attachAuxEffect(%d)", mConnId, effectId);
1058 Mutex::Autolock l(mLock);
1059 if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId);
1060 return NO_ERROR;
1061}
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001062
Gloria Wangd01ec6e2011-04-25 17:28:22 -07001063status_t MediaPlayerService::Client::setParameter(int key, const Parcel &request) {
1064 LOGV("[%d] setParameter(%d)", mConnId, key);
1065 sp<MediaPlayerBase> p = getPlayer();
1066 if (p == 0) return UNKNOWN_ERROR;
1067 return p->setParameter(key, request);
1068}
1069
1070status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) {
1071 LOGV("[%d] getParameter(%d)", mConnId, key);
1072 sp<MediaPlayerBase> p = getPlayer();
1073 if (p == 0) return UNKNOWN_ERROR;
1074 return p->getParameter(key, reply);
1075}
1076
Gloria Wang162ee492011-04-11 17:23:27 -07001077void MediaPlayerService::Client::notify(
1078 void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079{
1080 Client* client = static_cast<Client*>(cookie);
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001081
1082 if (MEDIA_INFO == msg &&
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001083 MEDIA_INFO_METADATA_UPDATE == ext1) {
nikobc726922009-07-20 15:07:26 -07001084 const media::Metadata::Type metadata_type = ext2;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001085
1086 if(client->shouldDropMetadata(metadata_type)) {
1087 return;
1088 }
1089
1090 // Update the list of metadata that have changed. getMetadata
1091 // also access mMetadataUpdated and clears it.
1092 client->addNewMetadataUpdate(metadata_type);
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001093 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
Gloria Wang162ee492011-04-11 17:23:27 -07001095 client->mClient->notify(msg, ext1, ext2, obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096}
1097
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001098
nikobc726922009-07-20 15:07:26 -07001099bool MediaPlayerService::Client::shouldDropMetadata(media::Metadata::Type code) const
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001100{
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001101 Mutex::Autolock lock(mLock);
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001102
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001103 if (findMetadata(mMetadataDrop, code)) {
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001104 return true;
1105 }
1106
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001107 if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001108 return false;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001109 } else {
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001110 return true;
1111 }
1112}
1113
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001114
nikobc726922009-07-20 15:07:26 -07001115void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001116 Mutex::Autolock lock(mLock);
1117 if (mMetadataUpdated.indexOf(metadata_type) < 0) {
1118 mMetadataUpdated.add(metadata_type);
1119 }
1120}
1121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122#if CALLBACK_ANTAGONIZER
1123const int Antagonizer::interval = 10000; // 10 msecs
1124
1125Antagonizer::Antagonizer(notify_callback_f cb, void* client) :
1126 mExit(false), mActive(false), mClient(client), mCb(cb)
1127{
1128 createThread(callbackThread, this);
1129}
1130
1131void Antagonizer::kill()
1132{
1133 Mutex::Autolock _l(mLock);
1134 mActive = false;
1135 mExit = true;
1136 mCondition.wait(mLock);
1137}
1138
1139int Antagonizer::callbackThread(void* user)
1140{
1141 LOGD("Antagonizer started");
1142 Antagonizer* p = reinterpret_cast<Antagonizer*>(user);
1143 while (!p->mExit) {
1144 if (p->mActive) {
1145 LOGV("send event");
1146 p->mCb(p->mClient, 0, 0, 0);
1147 }
1148 usleep(interval);
1149 }
1150 Mutex::Autolock _l(p->mLock);
1151 p->mCondition.signal();
1152 LOGD("Antagonizer stopped");
1153 return 0;
1154}
1155#endif
1156
1157static size_t kDefaultHeapSize = 1024 * 1024; // 1MB
1158
1159sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
1160{
1161 LOGV("decode(%s)", url);
1162 sp<MemoryBase> mem;
1163 sp<MediaPlayerBase> player;
1164
1165 // Protect our precious, precious DRMd ringtones by only allowing
1166 // decoding of http, but not filesystem paths or content Uris.
1167 // If the application wants to decode those, it should open a
1168 // filedescriptor for them and use that.
1169 if (url != NULL && strncmp(url, "http://", 7) != 0) {
1170 LOGD("Can't decode %s by path, use filedescriptor instead", url);
1171 return mem;
1172 }
1173
1174 player_type playerType = getPlayerType(url);
1175 LOGV("player type = %d", playerType);
1176
1177 // create the right type of player
1178 sp<AudioCache> cache = new AudioCache(url);
1179 player = android::createPlayer(playerType, cache.get(), cache->notify);
1180 if (player == NULL) goto Exit;
1181 if (player->hardwareOutput()) goto Exit;
1182
1183 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1184
1185 // set data source
1186 if (player->setDataSource(url) != NO_ERROR) goto Exit;
1187
1188 LOGV("prepare");
1189 player->prepareAsync();
1190
1191 LOGV("wait for prepare");
1192 if (cache->wait() != NO_ERROR) goto Exit;
1193
1194 LOGV("start");
1195 player->start();
1196
1197 LOGV("wait for playback complete");
1198 if (cache->wait() != NO_ERROR) goto Exit;
1199
1200 mem = new MemoryBase(cache->getHeap(), 0, cache->size());
1201 *pSampleRate = cache->sampleRate();
1202 *pNumChannels = cache->channelCount();
Jean-Michel Trivi54392232011-05-24 15:53:33 -07001203 *pFormat = (int)cache->format();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
1205
1206Exit:
1207 if (player != 0) player->reset();
1208 return mem;
1209}
1210
1211sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
1212{
1213 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
1214 sp<MemoryBase> mem;
1215 sp<MediaPlayerBase> player;
1216
1217 player_type playerType = getPlayerType(fd, offset, length);
1218 LOGV("player type = %d", playerType);
1219
1220 // create the right type of player
1221 sp<AudioCache> cache = new AudioCache("decode_fd");
1222 player = android::createPlayer(playerType, cache.get(), cache->notify);
1223 if (player == NULL) goto Exit;
1224 if (player->hardwareOutput()) goto Exit;
1225
1226 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1227
1228 // set data source
1229 if (player->setDataSource(fd, offset, length) != NO_ERROR) goto Exit;
1230
1231 LOGV("prepare");
1232 player->prepareAsync();
1233
1234 LOGV("wait for prepare");
1235 if (cache->wait() != NO_ERROR) goto Exit;
1236
1237 LOGV("start");
1238 player->start();
1239
1240 LOGV("wait for playback complete");
1241 if (cache->wait() != NO_ERROR) goto Exit;
1242
1243 mem = new MemoryBase(cache->getHeap(), 0, cache->size());
1244 *pSampleRate = cache->sampleRate();
1245 *pNumChannels = cache->channelCount();
1246 *pFormat = cache->format();
1247 LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
1248
1249Exit:
1250 if (player != 0) player->reset();
1251 ::close(fd);
1252 return mem;
1253}
1254
Marco Nelissenc39d2e32009-09-20 10:42:13 -07001255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256#undef LOG_TAG
1257#define LOG_TAG "AudioSink"
Eric Laurent619346f2010-06-21 09:27:30 -07001258MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
Andreas Hubere46b7be2009-07-14 16:56:47 -07001259 : mCallback(NULL),
Eric Laurent619346f2010-06-21 09:27:30 -07001260 mCallbackCookie(NULL),
1261 mSessionId(sessionId) {
1262 LOGV("AudioOutput(%d)", sessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 mTrack = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001264 mStreamType = AUDIO_STREAM_MUSIC;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 mLeftVolume = 1.0;
1266 mRightVolume = 1.0;
1267 mLatency = 0;
1268 mMsecsPerFrame = 0;
Eric Laurent7070b362010-07-16 07:43:46 -07001269 mAuxEffectId = 0;
1270 mSendLevel = 0.0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 setMinBufferCount();
1272}
1273
1274MediaPlayerService::AudioOutput::~AudioOutput()
1275{
1276 close();
1277}
1278
1279void MediaPlayerService::AudioOutput::setMinBufferCount()
1280{
1281 char value[PROPERTY_VALUE_MAX];
1282 if (property_get("ro.kernel.qemu", value, 0)) {
1283 mIsOnEmulator = true;
1284 mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
1285 }
1286}
1287
1288bool MediaPlayerService::AudioOutput::isOnEmulator()
1289{
1290 setMinBufferCount();
1291 return mIsOnEmulator;
1292}
1293
1294int MediaPlayerService::AudioOutput::getMinBufferCount()
1295{
1296 setMinBufferCount();
1297 return mMinBufferCount;
1298}
1299
1300ssize_t MediaPlayerService::AudioOutput::bufferSize() const
1301{
1302 if (mTrack == 0) return NO_INIT;
1303 return mTrack->frameCount() * frameSize();
1304}
1305
1306ssize_t MediaPlayerService::AudioOutput::frameCount() const
1307{
1308 if (mTrack == 0) return NO_INIT;
1309 return mTrack->frameCount();
1310}
1311
1312ssize_t MediaPlayerService::AudioOutput::channelCount() const
1313{
1314 if (mTrack == 0) return NO_INIT;
1315 return mTrack->channelCount();
1316}
1317
1318ssize_t MediaPlayerService::AudioOutput::frameSize() const
1319{
1320 if (mTrack == 0) return NO_INIT;
1321 return mTrack->frameSize();
1322}
1323
1324uint32_t MediaPlayerService::AudioOutput::latency () const
1325{
1326 return mLatency;
1327}
1328
1329float MediaPlayerService::AudioOutput::msecsPerFrame() const
1330{
1331 return mMsecsPerFrame;
1332}
1333
Eric Laurent0986e792010-01-19 17:37:09 -08001334status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position)
1335{
1336 if (mTrack == 0) return NO_INIT;
1337 return mTrack->getPosition(position);
1338}
1339
Andreas Hubere46b7be2009-07-14 16:56:47 -07001340status_t MediaPlayerService::AudioOutput::open(
1341 uint32_t sampleRate, int channelCount, int format, int bufferCount,
1342 AudioCallback cb, void *cookie)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343{
Andreas Hubere46b7be2009-07-14 16:56:47 -07001344 mCallback = cb;
1345 mCallbackCookie = cookie;
1346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 // Check argument "bufferCount" against the mininum buffer count
1348 if (bufferCount < mMinBufferCount) {
1349 LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
1350 bufferCount = mMinBufferCount;
1351
1352 }
Eric Laurent619346f2010-06-21 09:27:30 -07001353 LOGV("open(%u, %d, %d, %d, %d)", sampleRate, channelCount, format, bufferCount,mSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 if (mTrack) close();
1355 int afSampleRate;
1356 int afFrameCount;
1357 int frameCount;
1358
1359 if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
1360 return NO_INIT;
1361 }
1362 if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
1363 return NO_INIT;
1364 }
1365
1366 frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001367
1368 AudioTrack *t;
1369 if (mCallback != NULL) {
1370 t = new AudioTrack(
Eric Laurenta553c252009-07-17 12:17:14 -07001371 mStreamType,
1372 sampleRate,
1373 format,
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001374 (channelCount == 2) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO,
Eric Laurenta553c252009-07-17 12:17:14 -07001375 frameCount,
1376 0 /* flags */,
1377 CallbackWrapper,
Eric Laurent619346f2010-06-21 09:27:30 -07001378 this,
1379 0,
1380 mSessionId);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001381 } else {
1382 t = new AudioTrack(
Eric Laurenta553c252009-07-17 12:17:14 -07001383 mStreamType,
1384 sampleRate,
1385 format,
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001386 (channelCount == 2) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO,
Eric Laurent619346f2010-06-21 09:27:30 -07001387 frameCount,
1388 0,
1389 NULL,
1390 NULL,
1391 0,
1392 mSessionId);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001393 }
1394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 if ((t == 0) || (t->initCheck() != NO_ERROR)) {
1396 LOGE("Unable to create audio track");
1397 delete t;
1398 return NO_INIT;
1399 }
1400
1401 LOGV("setVolume");
1402 t->setVolume(mLeftVolume, mRightVolume);
Eric Laurent7070b362010-07-16 07:43:46 -07001403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Dave Sparksb904c2a2009-12-03 10:13:32 -08001405 mLatency = t->latency();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 mTrack = t;
Eric Laurent7070b362010-07-16 07:43:46 -07001407
1408 t->setAuxEffectSendLevel(mSendLevel);
1409 return t->attachAuxEffect(mAuxEffectId);;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410}
1411
1412void MediaPlayerService::AudioOutput::start()
1413{
1414 LOGV("start");
1415 if (mTrack) {
1416 mTrack->setVolume(mLeftVolume, mRightVolume);
Eric Laurent7070b362010-07-16 07:43:46 -07001417 mTrack->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 mTrack->start();
1419 }
1420}
1421
Marco Nelissene274db12010-01-12 09:23:54 -08001422
1423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
1425{
Andreas Hubere46b7be2009-07-14 16:56:47 -07001426 LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
1427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 //LOGV("write(%p, %u)", buffer, size);
Marco Nelissenc39d2e32009-09-20 10:42:13 -07001429 if (mTrack) {
Marco Nelissenc39d2e32009-09-20 10:42:13 -07001430 ssize_t ret = mTrack->write(buffer, size);
Marco Nelissenc39d2e32009-09-20 10:42:13 -07001431 return ret;
1432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 return NO_INIT;
1434}
1435
1436void MediaPlayerService::AudioOutput::stop()
1437{
1438 LOGV("stop");
1439 if (mTrack) mTrack->stop();
1440}
1441
1442void MediaPlayerService::AudioOutput::flush()
1443{
1444 LOGV("flush");
1445 if (mTrack) mTrack->flush();
1446}
1447
1448void MediaPlayerService::AudioOutput::pause()
1449{
1450 LOGV("pause");
1451 if (mTrack) mTrack->pause();
1452}
1453
1454void MediaPlayerService::AudioOutput::close()
1455{
1456 LOGV("close");
1457 delete mTrack;
1458 mTrack = 0;
1459}
1460
1461void MediaPlayerService::AudioOutput::setVolume(float left, float right)
1462{
1463 LOGV("setVolume(%f, %f)", left, right);
1464 mLeftVolume = left;
1465 mRightVolume = right;
1466 if (mTrack) {
1467 mTrack->setVolume(left, right);
1468 }
1469}
1470
Eric Laurent7070b362010-07-16 07:43:46 -07001471status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
1472{
1473 LOGV("setAuxEffectSendLevel(%f)", level);
1474 mSendLevel = level;
1475 if (mTrack) {
1476 return mTrack->setAuxEffectSendLevel(level);
1477 }
1478 return NO_ERROR;
1479}
1480
1481status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
1482{
1483 LOGV("attachAuxEffect(%d)", effectId);
1484 mAuxEffectId = effectId;
1485 if (mTrack) {
1486 return mTrack->attachAuxEffect(effectId);
1487 }
1488 return NO_ERROR;
1489}
1490
Andreas Hubere46b7be2009-07-14 16:56:47 -07001491// static
1492void MediaPlayerService::AudioOutput::CallbackWrapper(
Glenn Kastene46a86f2011-06-01 15:20:35 -07001493 int event, void *cookie, void *info) {
Marco Nelissene274db12010-01-12 09:23:54 -08001494 //LOGV("callbackwrapper");
Andreas Hubere46b7be2009-07-14 16:56:47 -07001495 if (event != AudioTrack::EVENT_MORE_DATA) {
1496 return;
1497 }
1498
1499 AudioOutput *me = (AudioOutput *)cookie;
1500 AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
1501
Andreas Huber6ed937e2010-02-09 16:59:18 -08001502 size_t actualSize = (*me->mCallback)(
Andreas Hubere46b7be2009-07-14 16:56:47 -07001503 me, buffer->raw, buffer->size, me->mCallbackCookie);
Andreas Huber6ed937e2010-02-09 16:59:18 -08001504
Andreas Huberc6e3b272011-04-04 11:43:40 -07001505 if (actualSize == 0 && buffer->size > 0) {
1506 // We've reached EOS but the audio track is not stopped yet,
1507 // keep playing silence.
Andreas Huber406a18b2010-02-18 16:45:13 -08001508
Andreas Huberc6e3b272011-04-04 11:43:40 -07001509 memset(buffer->raw, 0, buffer->size);
1510 actualSize = buffer->size;
1511 }
1512
1513 buffer->size = actualSize;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001514}
1515
Eric Laurentb3bdf3f2010-10-07 18:23:03 -07001516int MediaPlayerService::AudioOutput::getSessionId()
1517{
1518 return mSessionId;
1519}
1520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521#undef LOG_TAG
1522#define LOG_TAG "AudioCache"
1523MediaPlayerService::AudioCache::AudioCache(const char* name) :
1524 mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
1525 mError(NO_ERROR), mCommandComplete(false)
1526{
1527 // create ashmem heap
1528 mHeap = new MemoryHeapBase(kDefaultHeapSize, 0, name);
1529}
1530
1531uint32_t MediaPlayerService::AudioCache::latency () const
1532{
1533 return 0;
1534}
1535
1536float MediaPlayerService::AudioCache::msecsPerFrame() const
1537{
1538 return mMsecsPerFrame;
1539}
1540
Eric Laurent0986e792010-01-19 17:37:09 -08001541status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position)
1542{
1543 if (position == 0) return BAD_VALUE;
1544 *position = mSize;
1545 return NO_ERROR;
1546}
1547
Andreas Huber6ed937e2010-02-09 16:59:18 -08001548////////////////////////////////////////////////////////////////////////////////
1549
1550struct CallbackThread : public Thread {
1551 CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink,
1552 MediaPlayerBase::AudioSink::AudioCallback cb,
1553 void *cookie);
1554
1555protected:
1556 virtual ~CallbackThread();
1557
1558 virtual bool threadLoop();
1559
1560private:
1561 wp<MediaPlayerBase::AudioSink> mSink;
1562 MediaPlayerBase::AudioSink::AudioCallback mCallback;
1563 void *mCookie;
1564 void *mBuffer;
1565 size_t mBufferSize;
1566
1567 CallbackThread(const CallbackThread &);
1568 CallbackThread &operator=(const CallbackThread &);
1569};
1570
1571CallbackThread::CallbackThread(
1572 const wp<MediaPlayerBase::AudioSink> &sink,
1573 MediaPlayerBase::AudioSink::AudioCallback cb,
1574 void *cookie)
1575 : mSink(sink),
1576 mCallback(cb),
1577 mCookie(cookie),
1578 mBuffer(NULL),
1579 mBufferSize(0) {
1580}
1581
1582CallbackThread::~CallbackThread() {
1583 if (mBuffer) {
1584 free(mBuffer);
1585 mBuffer = NULL;
1586 }
1587}
1588
1589bool CallbackThread::threadLoop() {
1590 sp<MediaPlayerBase::AudioSink> sink = mSink.promote();
1591 if (sink == NULL) {
1592 return false;
1593 }
1594
1595 if (mBuffer == NULL) {
1596 mBufferSize = sink->bufferSize();
1597 mBuffer = malloc(mBufferSize);
1598 }
1599
1600 size_t actualSize =
1601 (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie);
1602
1603 if (actualSize > 0) {
1604 sink->write(mBuffer, actualSize);
1605 }
1606
1607 return true;
1608}
1609
1610////////////////////////////////////////////////////////////////////////////////
1611
Andreas Hubere46b7be2009-07-14 16:56:47 -07001612status_t MediaPlayerService::AudioCache::open(
1613 uint32_t sampleRate, int channelCount, int format, int bufferCount,
1614 AudioCallback cb, void *cookie)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615{
Dave Sparks14f89402009-12-09 20:20:26 -08001616 LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
Dave Sparks14f89402009-12-09 20:20:26 -08001617 if (mHeap->getHeapID() < 0) {
1618 return NO_INIT;
1619 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 mSampleRate = sampleRate;
1622 mChannelCount = (uint16_t)channelCount;
1623 mFormat = (uint16_t)format;
1624 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Andreas Huber6ed937e2010-02-09 16:59:18 -08001625
1626 if (cb != NULL) {
1627 mCallbackThread = new CallbackThread(this, cb, cookie);
1628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 return NO_ERROR;
1630}
1631
Andreas Huber6ed937e2010-02-09 16:59:18 -08001632void MediaPlayerService::AudioCache::start() {
1633 if (mCallbackThread != NULL) {
1634 mCallbackThread->run("AudioCache callback");
1635 }
1636}
1637
1638void MediaPlayerService::AudioCache::stop() {
1639 if (mCallbackThread != NULL) {
1640 mCallbackThread->requestExitAndWait();
1641 }
1642}
1643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
1645{
1646 LOGV("write(%p, %u)", buffer, size);
1647 if ((buffer == 0) || (size == 0)) return size;
1648
1649 uint8_t* p = static_cast<uint8_t*>(mHeap->getBase());
1650 if (p == NULL) return NO_INIT;
1651 p += mSize;
1652 LOGV("memcpy(%p, %p, %u)", p, buffer, size);
1653 if (mSize + size > mHeap->getSize()) {
1654 LOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
1655 size = mHeap->getSize() - mSize;
1656 }
1657 memcpy(p, buffer, size);
1658 mSize += size;
1659 return size;
1660}
1661
1662// call with lock held
1663status_t MediaPlayerService::AudioCache::wait()
1664{
1665 Mutex::Autolock lock(mLock);
Dave Sparks16433e22010-03-01 19:29:58 -08001666 while (!mCommandComplete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 mSignal.wait(mLock);
1668 }
1669 mCommandComplete = false;
1670
1671 if (mError == NO_ERROR) {
1672 LOGV("wait - success");
1673 } else {
1674 LOGV("wait - error");
1675 }
1676 return mError;
1677}
1678
Gloria Wang162ee492011-04-11 17:23:27 -07001679void MediaPlayerService::AudioCache::notify(
1680 void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681{
1682 LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
1683 AudioCache* p = static_cast<AudioCache*>(cookie);
1684
1685 // ignore buffering messages
Dave Sparks14f89402009-12-09 20:20:26 -08001686 switch (msg)
1687 {
1688 case MEDIA_ERROR:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 LOGE("Error %d, %d occurred", ext1, ext2);
1690 p->mError = ext1;
Dave Sparks14f89402009-12-09 20:20:26 -08001691 break;
1692 case MEDIA_PREPARED:
1693 LOGV("prepared");
1694 break;
1695 case MEDIA_PLAYBACK_COMPLETE:
1696 LOGV("playback complete");
1697 break;
1698 default:
1699 LOGV("ignored");
1700 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 }
1702
1703 // wake up thread
Dave Sparks6c26fe42010-03-02 12:56:37 -08001704 Mutex::Autolock lock(p->mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 p->mCommandComplete = true;
1706 p->mSignal.signal();
1707}
1708
Eric Laurentb3bdf3f2010-10-07 18:23:03 -07001709int MediaPlayerService::AudioCache::getSessionId()
1710{
1711 return 0;
1712}
1713
Gloria Wangd211f412011-02-19 18:37:57 -08001714void MediaPlayerService::addBatteryData(uint32_t params)
1715{
1716 Mutex::Autolock lock(mLock);
Gloria Wang9b3f1522011-02-24 14:51:45 -08001717
1718 int32_t time = systemTime() / 1000000L;
1719
1720 // change audio output devices. This notification comes from AudioFlinger
1721 if ((params & kBatteryDataSpeakerOn)
1722 || (params & kBatteryDataOtherAudioDeviceOn)) {
1723
1724 int deviceOn[NUM_AUDIO_DEVICES];
1725 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1726 deviceOn[i] = 0;
1727 }
1728
1729 if ((params & kBatteryDataSpeakerOn)
1730 && (params & kBatteryDataOtherAudioDeviceOn)) {
1731 deviceOn[SPEAKER_AND_OTHER] = 1;
1732 } else if (params & kBatteryDataSpeakerOn) {
1733 deviceOn[SPEAKER] = 1;
1734 } else {
1735 deviceOn[OTHER_AUDIO_DEVICE] = 1;
1736 }
1737
1738 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1739 if (mBatteryAudio.deviceOn[i] != deviceOn[i]){
1740
1741 if (mBatteryAudio.refCount > 0) { // if playing audio
1742 if (!deviceOn[i]) {
1743 mBatteryAudio.lastTime[i] += time;
1744 mBatteryAudio.totalTime[i] += mBatteryAudio.lastTime[i];
1745 mBatteryAudio.lastTime[i] = 0;
1746 } else {
1747 mBatteryAudio.lastTime[i] = 0 - time;
1748 }
1749 }
1750
1751 mBatteryAudio.deviceOn[i] = deviceOn[i];
1752 }
1753 }
1754 return;
1755 }
1756
1757 // an sudio stream is started
1758 if (params & kBatteryDataAudioFlingerStart) {
1759 // record the start time only if currently no other audio
1760 // is being played
1761 if (mBatteryAudio.refCount == 0) {
1762 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1763 if (mBatteryAudio.deviceOn[i]) {
1764 mBatteryAudio.lastTime[i] -= time;
1765 }
1766 }
1767 }
1768
1769 mBatteryAudio.refCount ++;
1770 return;
1771
1772 } else if (params & kBatteryDataAudioFlingerStop) {
1773 if (mBatteryAudio.refCount <= 0) {
1774 LOGW("Battery track warning: refCount is <= 0");
1775 return;
1776 }
1777
1778 // record the stop time only if currently this is the only
1779 // audio being played
1780 if (mBatteryAudio.refCount == 1) {
1781 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1782 if (mBatteryAudio.deviceOn[i]) {
1783 mBatteryAudio.lastTime[i] += time;
1784 mBatteryAudio.totalTime[i] += mBatteryAudio.lastTime[i];
1785 mBatteryAudio.lastTime[i] = 0;
1786 }
1787 }
1788 }
1789
1790 mBatteryAudio.refCount --;
1791 return;
1792 }
1793
Gloria Wangd211f412011-02-19 18:37:57 -08001794 int uid = IPCThreadState::self()->getCallingUid();
1795 if (uid == AID_MEDIA) {
1796 return;
1797 }
1798 int index = mBatteryData.indexOfKey(uid);
Gloria Wangd211f412011-02-19 18:37:57 -08001799
1800 if (index < 0) { // create a new entry for this UID
1801 BatteryUsageInfo info;
1802 info.audioTotalTime = 0;
1803 info.videoTotalTime = 0;
1804 info.audioLastTime = 0;
1805 info.videoLastTime = 0;
1806 info.refCount = 0;
1807
Gloria Wang9b3f1522011-02-24 14:51:45 -08001808 if (mBatteryData.add(uid, info) == NO_MEMORY) {
1809 LOGE("Battery track error: no memory for new app");
1810 return;
1811 }
Gloria Wangd211f412011-02-19 18:37:57 -08001812 }
1813
1814 BatteryUsageInfo &info = mBatteryData.editValueFor(uid);
1815
1816 if (params & kBatteryDataCodecStarted) {
1817 if (params & kBatteryDataTrackAudio) {
1818 info.audioLastTime -= time;
1819 info.refCount ++;
1820 }
1821 if (params & kBatteryDataTrackVideo) {
1822 info.videoLastTime -= time;
1823 info.refCount ++;
1824 }
1825 } else {
1826 if (info.refCount == 0) {
1827 LOGW("Battery track warning: refCount is already 0");
1828 return;
1829 } else if (info.refCount < 0) {
1830 LOGE("Battery track error: refCount < 0");
1831 mBatteryData.removeItem(uid);
1832 return;
1833 }
1834
1835 if (params & kBatteryDataTrackAudio) {
1836 info.audioLastTime += time;
1837 info.refCount --;
1838 }
1839 if (params & kBatteryDataTrackVideo) {
1840 info.videoLastTime += time;
1841 info.refCount --;
1842 }
1843
1844 // no stream is being played by this UID
1845 if (info.refCount == 0) {
1846 info.audioTotalTime += info.audioLastTime;
1847 info.audioLastTime = 0;
1848 info.videoTotalTime += info.videoLastTime;
1849 info.videoLastTime = 0;
1850 }
1851 }
1852}
1853
1854status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
1855 Mutex::Autolock lock(mLock);
Gloria Wang9b3f1522011-02-24 14:51:45 -08001856
1857 // audio output devices usage
1858 int32_t time = systemTime() / 1000000L; //in ms
1859 int32_t totalTime;
1860
1861 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1862 totalTime = mBatteryAudio.totalTime[i];
1863
1864 if (mBatteryAudio.deviceOn[i]
1865 && (mBatteryAudio.lastTime[i] != 0)) {
1866 int32_t tmpTime = mBatteryAudio.lastTime[i] + time;
1867 totalTime += tmpTime;
1868 }
1869
1870 reply->writeInt32(totalTime);
1871 // reset the total time
1872 mBatteryAudio.totalTime[i] = 0;
1873 }
1874
1875 // codec usage
Gloria Wangd211f412011-02-19 18:37:57 -08001876 BatteryUsageInfo info;
1877 int size = mBatteryData.size();
1878
1879 reply->writeInt32(size);
1880 int i = 0;
1881
1882 while (i < size) {
1883 info = mBatteryData.valueAt(i);
1884
1885 reply->writeInt32(mBatteryData.keyAt(i)); //UID
1886 reply->writeInt32(info.audioTotalTime);
1887 reply->writeInt32(info.videoTotalTime);
1888
1889 info.audioTotalTime = 0;
1890 info.videoTotalTime = 0;
1891
1892 // remove the UID entry where no stream is being played
1893 if (info.refCount <= 0) {
1894 mBatteryData.removeItemsAt(i);
1895 size --;
1896 i --;
1897 }
1898 i++;
1899 }
1900 return NO_ERROR;
1901}
nikobc726922009-07-20 15:07:26 -07001902} // namespace android