blob: 8c6f76b1999643c9301b779002e5b183b69e8fb0 [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>
54
Gloria Wangd211f412011-02-19 18:37:57 -080055#include <private/android_filesystem_config.h>
56
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057#include "MediaRecorderClient.h"
58#include "MediaPlayerService.h"
59#include "MetadataRetrieverClient.h"
60
61#include "MidiFile.h"
Nicolas Catania8f5fcab2009-07-13 14:37:49 -070062#include "TestPlayerStub.h"
Andreas Hubere46b7be2009-07-14 16:56:47 -070063#include "StagefrightPlayer.h"
Andreas Hubera1587462010-12-15 15:17:42 -080064#include "nuplayer/NuPlayerDriver.h"
Andreas Hubere46b7be2009-07-14 16:56:47 -070065
Andreas Hubere46b7be2009-07-14 16:56:47 -070066#include <OMX.h>
Nicolas Catania8f5fcab2009-07-13 14:37:49 -070067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068/* desktop Linux needs a little help with gettid() */
69#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
70#define __KERNEL__
71# include <linux/unistd.h>
72#ifdef _syscall0
73_syscall0(pid_t,gettid)
74#else
75pid_t gettid() { return syscall(__NR_gettid);}
76#endif
77#undef __KERNEL__
78#endif
79
Nicolas Cataniab2c69392009-07-08 08:57:42 -070080namespace {
nikobc726922009-07-20 15:07:26 -070081using android::media::Metadata;
Nicolas Cataniab2c69392009-07-08 08:57:42 -070082using android::status_t;
83using android::OK;
84using android::BAD_VALUE;
85using android::NOT_ENOUGH_DATA;
86using android::Parcel;
Nicolas Cataniab2c69392009-07-08 08:57:42 -070087
88// Max number of entries in the filter.
89const int kMaxFilterSize = 64; // I pulled that out of thin air.
90
nikobc726922009-07-20 15:07:26 -070091// FIXME: Move all the metadata related function in the Metadata.cpp
niko89948372009-07-16 16:39:53 -070092
Nicolas Cataniab2c69392009-07-08 08:57:42 -070093
94// Unmarshall a filter from a Parcel.
95// Filter format in a parcel:
96//
97// 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
98// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99// | number of entries (n) |
100// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101// | metadata type 1 |
102// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103// | metadata type 2 |
104// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105// ....
106// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107// | metadata type n |
108// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109//
110// @param p Parcel that should start with a filter.
111// @param[out] filter On exit contains the list of metadata type to be
112// filtered.
113// @param[out] status On exit contains the status code to be returned.
114// @return true if the parcel starts with a valid filter.
115bool unmarshallFilter(const Parcel& p,
nikobc726922009-07-20 15:07:26 -0700116 Metadata::Filter *filter,
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700117 status_t *status)
118{
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700119 int32_t val;
120 if (p.readInt32(&val) != OK)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700121 {
122 LOGE("Failed to read filter's length");
123 *status = NOT_ENOUGH_DATA;
124 return false;
125 }
126
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700127 if( val > kMaxFilterSize || val < 0)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700128 {
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700129 LOGE("Invalid filter len %d", val);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700130 *status = BAD_VALUE;
131 return false;
132 }
133
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700134 const size_t num = val;
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700135
136 filter->clear();
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700137 filter->setCapacity(num);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700138
nikobc726922009-07-20 15:07:26 -0700139 size_t size = num * sizeof(Metadata::Type);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700140
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700141
142 if (p.dataAvail() < size)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700143 {
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700144 LOGE("Filter too short expected %d but got %d", size, p.dataAvail());
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700145 *status = NOT_ENOUGH_DATA;
146 return false;
147 }
148
nikobc726922009-07-20 15:07:26 -0700149 const Metadata::Type *data =
150 static_cast<const Metadata::Type*>(p.readInplace(size));
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700151
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700152 if (NULL == data)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700153 {
154 LOGE("Filter had no data");
155 *status = BAD_VALUE;
156 return false;
157 }
158
159 // TODO: The stl impl of vector would be more efficient here
160 // because it degenerates into a memcpy on pod types. Try to
161 // replace later or use stl::set.
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700162 for (size_t i = 0; i < num; ++i)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700163 {
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700164 filter->add(*data);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700165 ++data;
166 }
167 *status = OK;
168 return true;
169}
170
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700171// @param filter Of metadata type.
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700172// @param val To be searched.
173// @return true if a match was found.
nikobc726922009-07-20 15:07:26 -0700174bool findMetadata(const Metadata::Filter& filter, const int32_t val)
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700175{
176 // Deal with empty and ANY right away
177 if (filter.isEmpty()) return false;
nikobc726922009-07-20 15:07:26 -0700178 if (filter[0] == Metadata::kAny) return true;
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700179
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700180 return filter.indexOf(val) >= 0;
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700181}
182
183} // anonymous namespace
184
185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186namespace android {
187
188// TODO: Temp hack until we can register players
189typedef struct {
190 const char *extension;
191 const player_type playertype;
192} extmap;
193extmap FILE_EXTS [] = {
194 {".mid", SONIVOX_PLAYER},
195 {".midi", SONIVOX_PLAYER},
196 {".smf", SONIVOX_PLAYER},
197 {".xmf", SONIVOX_PLAYER},
198 {".imy", SONIVOX_PLAYER},
199 {".rtttl", SONIVOX_PLAYER},
200 {".rtx", SONIVOX_PLAYER},
201 {".ota", SONIVOX_PLAYER},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202};
203
204// 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 -0800205/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
206/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
207
208void MediaPlayerService::instantiate() {
209 defaultServiceManager()->addService(
210 String16("media.player"), new MediaPlayerService());
211}
212
213MediaPlayerService::MediaPlayerService()
214{
215 LOGV("MediaPlayerService created");
216 mNextConnId = 1;
217}
218
219MediaPlayerService::~MediaPlayerService()
220{
221 LOGV("MediaPlayerService destroyed");
222}
223
224sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
225{
Gloria Wang608a2632009-10-29 15:46:37 -0700226 sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid);
227 wp<MediaRecorderClient> w = recorder;
228 Mutex::Autolock lock(mLock);
229 mMediaRecorderClients.add(w);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 LOGV("Create new media recorder client from pid %d", pid);
231 return recorder;
232}
233
Gloria Wang608a2632009-10-29 15:46:37 -0700234void MediaPlayerService::removeMediaRecorderClient(wp<MediaRecorderClient> client)
235{
236 Mutex::Autolock lock(mLock);
237 mMediaRecorderClients.remove(client);
238 LOGV("Delete media recorder client");
239}
240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pid)
242{
243 sp<MetadataRetrieverClient> retriever = new MetadataRetrieverClient(pid);
244 LOGV("Create new media retriever from pid %d", pid);
245 return retriever;
246}
247
Andreas Huber25643002010-01-28 11:19:57 -0800248sp<IMediaPlayer> MediaPlayerService::create(
249 pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
Eric Laurent619346f2010-06-21 09:27:30 -0700250 const KeyedVector<String8, String8> *headers, int audioSessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251{
252 int32_t connId = android_atomic_inc(&mNextConnId);
Eric Laurent619346f2010-06-21 09:27:30 -0700253 sp<Client> c = new Client(this, pid, connId, client, audioSessionId);
254 LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d",
255 connId, pid, url, connId, audioSessionId);
Andreas Huber25643002010-01-28 11:19:57 -0800256 if (NO_ERROR != c->setDataSource(url, headers))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 {
258 c.clear();
259 return c;
260 }
261 wp<Client> w = c;
262 Mutex::Autolock lock(mLock);
263 mClients.add(w);
264 return c;
265}
266
267sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,
Eric Laurent619346f2010-06-21 09:27:30 -0700268 int fd, int64_t offset, int64_t length, int audioSessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269{
270 int32_t connId = android_atomic_inc(&mNextConnId);
Eric Laurent619346f2010-06-21 09:27:30 -0700271 sp<Client> c = new Client(this, pid, connId, client, audioSessionId);
272 LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld, audioSessionId=%d",
273 connId, pid, fd, offset, length, audioSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 if (NO_ERROR != c->setDataSource(fd, offset, length)) {
275 c.clear();
276 } else {
277 wp<Client> w = c;
278 Mutex::Autolock lock(mLock);
279 mClients.add(w);
280 }
281 ::close(fd);
282 return c;
283}
284
Andreas Huber52b52cd2010-11-23 11:41:34 -0800285sp<IMediaPlayer> MediaPlayerService::create(
286 pid_t pid, const sp<IMediaPlayerClient> &client,
287 const sp<IStreamSource> &source, int audioSessionId) {
288 int32_t connId = android_atomic_inc(&mNextConnId);
289 sp<Client> c = new Client(this, pid, connId, client, audioSessionId);
290
291 LOGV("Create new client(%d) from pid %d, audioSessionId=%d",
292 connId, pid, audioSessionId);
293
294 if (OK != c->setDataSource(source)) {
295 c.clear();
296 } else {
297 wp<Client> w = c;
298 Mutex::Autolock lock(mLock);
299 mClients.add(w);
300 }
301
302 return c;
303}
304
Andreas Huber784202e2009-10-15 13:46:54 -0700305sp<IOMX> MediaPlayerService::getOMX() {
306 Mutex::Autolock autoLock(mLock);
307
308 if (mOMX.get() == NULL) {
309 mOMX = new OMX;
310 }
311
312 return mOMX;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700313}
314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
316{
317 const size_t SIZE = 256;
318 char buffer[SIZE];
319 String8 result;
320
321 result.append(" AudioCache\n");
322 if (mHeap != 0) {
323 snprintf(buffer, 255, " heap base(%p), size(%d), flags(%d), device(%s)\n",
324 mHeap->getBase(), mHeap->getSize(), mHeap->getFlags(), mHeap->getDevice());
325 result.append(buffer);
326 }
327 snprintf(buffer, 255, " msec per frame(%f), channel count(%d), format(%d), frame count(%ld)\n",
328 mMsecsPerFrame, mChannelCount, mFormat, mFrameCount);
329 result.append(buffer);
330 snprintf(buffer, 255, " sample rate(%d), size(%d), error(%d), command complete(%s)\n",
331 mSampleRate, mSize, mError, mCommandComplete?"true":"false");
332 result.append(buffer);
333 ::write(fd, result.string(), result.size());
334 return NO_ERROR;
335}
336
337status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& args) const
338{
339 const size_t SIZE = 256;
340 char buffer[SIZE];
341 String8 result;
342
343 result.append(" AudioOutput\n");
344 snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
345 mStreamType, mLeftVolume, mRightVolume);
346 result.append(buffer);
347 snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
348 mMsecsPerFrame, mLatency);
349 result.append(buffer);
Eric Laurent7070b362010-07-16 07:43:46 -0700350 snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
351 mAuxEffectId, mSendLevel);
352 result.append(buffer);
353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 ::write(fd, result.string(), result.size());
355 if (mTrack != 0) {
356 mTrack->dump(fd, args);
357 }
358 return NO_ERROR;
359}
360
361status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args) const
362{
363 const size_t SIZE = 256;
364 char buffer[SIZE];
365 String8 result;
366 result.append(" Client\n");
367 snprintf(buffer, 255, " pid(%d), connId(%d), status(%d), looping(%s)\n",
368 mPid, mConnId, mStatus, mLoop?"true": "false");
369 result.append(buffer);
370 write(fd, result.string(), result.size());
371 if (mAudioOutput != 0) {
372 mAudioOutput->dump(fd, args);
373 }
374 write(fd, "\n", 1);
375 return NO_ERROR;
376}
377
378static int myTid() {
379#ifdef HAVE_GETTID
380 return gettid();
381#else
382 return getpid();
383#endif
384}
385
386#if defined(__arm__)
387extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
388 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
389extern "C" void free_malloc_leak_info(uint8_t* info);
390
Andreas Huber27123462009-10-27 15:50:04 -0700391// Use the String-class below instead of String8 to allocate all memory
392// beforehand and not reenter the heap while we are examining it...
393struct MyString8 {
394 static const size_t MAX_SIZE = 256 * 1024;
395
396 MyString8()
397 : mPtr((char *)malloc(MAX_SIZE)) {
398 *mPtr = '\0';
399 }
400
401 ~MyString8() {
402 free(mPtr);
403 }
404
405 void append(const char *s) {
406 strcat(mPtr, s);
407 }
408
409 const char *string() const {
410 return mPtr;
411 }
412
413 size_t size() const {
414 return strlen(mPtr);
415 }
416
417private:
418 char *mPtr;
419
420 MyString8(const MyString8 &);
421 MyString8 &operator=(const MyString8 &);
422};
423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424void memStatus(int fd, const Vector<String16>& args)
425{
426 const size_t SIZE = 256;
427 char buffer[SIZE];
Andreas Huber27123462009-10-27 15:50:04 -0700428 MyString8 result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429
430 typedef struct {
431 size_t size;
432 size_t dups;
433 intptr_t * backtrace;
434 } AllocEntry;
435
436 uint8_t *info = NULL;
437 size_t overallSize = 0;
438 size_t infoSize = 0;
439 size_t totalMemory = 0;
440 size_t backtraceSize = 0;
441
442 get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
443 if (info) {
444 uint8_t *ptr = info;
445 size_t count = overallSize / infoSize;
446
447 snprintf(buffer, SIZE, " Allocation count %i\n", count);
448 result.append(buffer);
James Dong3d23a612010-02-25 10:06:32 -0800449 snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
450 result.append(buffer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451
452 AllocEntry * entries = new AllocEntry[count];
453
454 for (size_t i = 0; i < count; i++) {
455 // Each entry should be size_t, size_t, intptr_t[backtraceSize]
456 AllocEntry *e = &entries[i];
457
458 e->size = *reinterpret_cast<size_t *>(ptr);
459 ptr += sizeof(size_t);
460
461 e->dups = *reinterpret_cast<size_t *>(ptr);
462 ptr += sizeof(size_t);
463
464 e->backtrace = reinterpret_cast<intptr_t *>(ptr);
465 ptr += sizeof(intptr_t) * backtraceSize;
466 }
467
468 // Now we need to sort the entries. They come sorted by size but
469 // not by stack trace which causes problems using diff.
470 bool moved;
471 do {
472 moved = false;
473 for (size_t i = 0; i < (count - 1); i++) {
474 AllocEntry *e1 = &entries[i];
475 AllocEntry *e2 = &entries[i+1];
476
477 bool swap = e1->size < e2->size;
478 if (e1->size == e2->size) {
479 for(size_t j = 0; j < backtraceSize; j++) {
480 if (e1->backtrace[j] == e2->backtrace[j]) {
481 continue;
482 }
483 swap = e1->backtrace[j] < e2->backtrace[j];
484 break;
485 }
486 }
487 if (swap) {
488 AllocEntry t = entries[i];
489 entries[i] = entries[i+1];
490 entries[i+1] = t;
491 moved = true;
492 }
493 }
494 } while (moved);
495
496 for (size_t i = 0; i < count; i++) {
497 AllocEntry *e = &entries[i];
498
James Dong3d23a612010-02-25 10:06:32 -0800499 snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 result.append(buffer);
501 for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
502 if (ct) {
503 result.append(", ");
504 }
505 snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
506 result.append(buffer);
507 }
508 result.append("\n");
509 }
510
511 delete[] entries;
512 free_malloc_leak_info(info);
513 }
514
515 write(fd, result.string(), result.size());
516}
517#endif
518
519status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
520{
521 const size_t SIZE = 256;
522 char buffer[SIZE];
523 String8 result;
524 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
525 snprintf(buffer, SIZE, "Permission Denial: "
526 "can't dump MediaPlayerService from pid=%d, uid=%d\n",
527 IPCThreadState::self()->getCallingPid(),
528 IPCThreadState::self()->getCallingUid());
529 result.append(buffer);
530 } else {
531 Mutex::Autolock lock(mLock);
532 for (int i = 0, n = mClients.size(); i < n; ++i) {
533 sp<Client> c = mClients[i].promote();
534 if (c != 0) c->dump(fd, args);
535 }
James Dong929642e2010-07-08 11:16:11 -0700536 if (mMediaRecorderClients.size() == 0) {
537 result.append(" No media recorder client\n\n");
538 } else {
539 for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
540 sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
541 snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
542 result.append(buffer);
543 write(fd, result.string(), result.size());
544 result = "\n";
545 c->dump(fd, args);
546 }
Gloria Wang608a2632009-10-29 15:46:37 -0700547 }
548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 result.append(" Files opened and/or mapped:\n");
550 snprintf(buffer, SIZE, "/proc/%d/maps", myTid());
551 FILE *f = fopen(buffer, "r");
552 if (f) {
553 while (!feof(f)) {
554 fgets(buffer, SIZE, f);
Dave Sparks124a3462010-09-27 16:55:18 -0700555 if (strstr(buffer, " /mnt/sdcard/") ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 strstr(buffer, " /system/sounds/") ||
Dave Sparks124a3462010-09-27 16:55:18 -0700557 strstr(buffer, " /data/") ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 strstr(buffer, " /system/media/")) {
559 result.append(" ");
560 result.append(buffer);
561 }
562 }
563 fclose(f);
564 } else {
565 result.append("couldn't open ");
566 result.append(buffer);
567 result.append("\n");
568 }
569
570 snprintf(buffer, SIZE, "/proc/%d/fd", myTid());
571 DIR *d = opendir(buffer);
572 if (d) {
573 struct dirent *ent;
574 while((ent = readdir(d)) != NULL) {
575 if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
576 snprintf(buffer, SIZE, "/proc/%d/fd/%s", myTid(), ent->d_name);
577 struct stat s;
578 if (lstat(buffer, &s) == 0) {
579 if ((s.st_mode & S_IFMT) == S_IFLNK) {
580 char linkto[256];
581 int len = readlink(buffer, linkto, sizeof(linkto));
582 if(len > 0) {
583 if(len > 255) {
584 linkto[252] = '.';
585 linkto[253] = '.';
586 linkto[254] = '.';
587 linkto[255] = 0;
588 } else {
589 linkto[len] = 0;
590 }
Dave Sparks124a3462010-09-27 16:55:18 -0700591 if (strstr(linkto, "/mnt/sdcard/") == linkto ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 strstr(linkto, "/system/sounds/") == linkto ||
Dave Sparks124a3462010-09-27 16:55:18 -0700593 strstr(linkto, "/data/") == linkto ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 strstr(linkto, "/system/media/") == linkto) {
595 result.append(" ");
596 result.append(buffer);
597 result.append(" -> ");
598 result.append(linkto);
599 result.append("\n");
600 }
601 }
602 } else {
603 result.append(" unexpected type for ");
604 result.append(buffer);
605 result.append("\n");
606 }
607 }
608 }
609 }
610 closedir(d);
611 } else {
612 result.append("couldn't open ");
613 result.append(buffer);
614 result.append("\n");
615 }
616
617#if defined(__arm__)
618 bool dumpMem = false;
619 for (size_t i = 0; i < args.size(); i++) {
620 if (args[i] == String16("-m")) {
621 dumpMem = true;
622 }
623 }
624 if (dumpMem) {
625 memStatus(fd, args);
626 }
627#endif
628 }
629 write(fd, result.string(), result.size());
630 return NO_ERROR;
631}
632
633void MediaPlayerService::removeClient(wp<Client> client)
634{
635 Mutex::Autolock lock(mLock);
636 mClients.remove(client);
637}
638
639MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t pid,
Eric Laurent619346f2010-06-21 09:27:30 -0700640 int32_t connId, const sp<IMediaPlayerClient>& client, int audioSessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641{
642 LOGV("Client(%d) constructor", connId);
643 mPid = pid;
644 mConnId = connId;
645 mService = service;
646 mClient = client;
647 mLoop = false;
648 mStatus = NO_INIT;
Eric Laurent619346f2010-06-21 09:27:30 -0700649 mAudioSessionId = audioSessionId;
650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651#if CALLBACK_ANTAGONIZER
652 LOGD("create Antagonizer");
653 mAntagonizer = new Antagonizer(notify, this);
654#endif
655}
656
657MediaPlayerService::Client::~Client()
658{
659 LOGV("Client(%d) destructor pid = %d", mConnId, mPid);
660 mAudioOutput.clear();
661 wp<Client> client(this);
662 disconnect();
663 mService->removeClient(client);
664}
665
666void MediaPlayerService::Client::disconnect()
667{
668 LOGV("disconnect(%d) from pid %d", mConnId, mPid);
669 // grab local reference and clear main reference to prevent future
670 // access to object
671 sp<MediaPlayerBase> p;
672 {
673 Mutex::Autolock l(mLock);
674 p = mPlayer;
675 }
Dave Sparkscb9a44e2009-03-24 17:57:12 -0700676 mClient.clear();
Andreas Hubere46b7be2009-07-14 16:56:47 -0700677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 mPlayer.clear();
679
680 // clear the notification to prevent callbacks to dead client
681 // and reset the player. We assume the player will serialize
682 // access to itself if necessary.
683 if (p != 0) {
684 p->setNotifyCallback(0, 0);
685#if CALLBACK_ANTAGONIZER
686 LOGD("kill Antagonizer");
687 mAntagonizer->kill();
688#endif
689 p->reset();
690 }
691
692 IPCThreadState::self()->flushCommands();
693}
694
Andreas Huber0d596d42009-08-07 09:30:32 -0700695static player_type getDefaultPlayerType() {
Andreas Huber8d65dd22010-06-23 16:40:57 -0700696 return STAGEFRIGHT_PLAYER;
Andreas Huber0d596d42009-08-07 09:30:32 -0700697}
698
James Dong392ff3b2009-09-06 14:29:45 -0700699player_type getPlayerType(int fd, int64_t offset, int64_t length)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700{
701 char buf[20];
702 lseek(fd, offset, SEEK_SET);
703 read(fd, buf, sizeof(buf));
704 lseek(fd, offset, SEEK_SET);
705
706 long ident = *((long*)buf);
707
708 // Ogg vorbis?
709 if (ident == 0x5367674f) // 'OggS'
Andreas Huber8d65dd22010-06-23 16:40:57 -0700710 return STAGEFRIGHT_PLAYER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711
712 // Some kind of MIDI?
713 EAS_DATA_HANDLE easdata;
714 if (EAS_Init(&easdata) == EAS_SUCCESS) {
715 EAS_FILE locator;
716 locator.path = NULL;
717 locator.fd = fd;
718 locator.offset = offset;
719 locator.length = length;
720 EAS_HANDLE eashandle;
721 if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
722 EAS_CloseFile(easdata, eashandle);
723 EAS_Shutdown(easdata);
724 return SONIVOX_PLAYER;
725 }
726 EAS_Shutdown(easdata);
727 }
728
Andreas Huber0d596d42009-08-07 09:30:32 -0700729 return getDefaultPlayerType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730}
731
James Dong392ff3b2009-09-06 14:29:45 -0700732player_type getPlayerType(const char* url)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733{
Nicolas Catania8f5fcab2009-07-13 14:37:49 -0700734 if (TestPlayerStub::canBeUsed(url)) {
735 return TEST_PLAYER;
736 }
737
Andreas Huberd6c421f2011-02-16 09:05:38 -0800738 if (!strncasecmp("http://", url, 7)) {
739 size_t len = strlen(url);
740 if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
741 return NU_PLAYER;
742 }
Andreas Huber54e66492010-12-23 10:27:40 -0800743
Andreas Huberd6c421f2011-02-16 09:05:38 -0800744 if (strstr(url,"m3u8")) {
745 return NU_PLAYER;
Andreas Huber54e66492010-12-23 10:27:40 -0800746 }
747 }
748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 // use MidiFile for MIDI extensions
750 int lenURL = strlen(url);
751 for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
752 int len = strlen(FILE_EXTS[i].extension);
753 int start = lenURL - len;
754 if (start > 0) {
Atsushi Enoebcc51d2010-03-19 23:18:02 +0900755 if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) {
Andreas Huber8d65dd22010-06-23 16:40:57 -0700756 return FILE_EXTS[i].playertype;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 }
758 }
759 }
760
Andreas Huber0d596d42009-08-07 09:30:32 -0700761 return getDefaultPlayerType();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762}
763
764static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
765 notify_callback_f notifyFunc)
766{
767 sp<MediaPlayerBase> p;
768 switch (playerType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 case SONIVOX_PLAYER:
770 LOGV(" create MidiFile");
771 p = new MidiFile();
772 break;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700773 case STAGEFRIGHT_PLAYER:
774 LOGV(" create StagefrightPlayer");
775 p = new StagefrightPlayer;
776 break;
Andreas Hubera1587462010-12-15 15:17:42 -0800777 case NU_PLAYER:
778 LOGV(" create NuPlayer");
779 p = new NuPlayerDriver;
780 break;
Nicolas Catania8f5fcab2009-07-13 14:37:49 -0700781 case TEST_PLAYER:
782 LOGV("Create Test Player stub");
783 p = new TestPlayerStub();
784 break;
James Dong8ec2d9a2010-11-10 18:42:40 -0800785 default:
786 LOGE("Unknown player type: %d", playerType);
787 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 }
789 if (p != NULL) {
790 if (p->initCheck() == NO_ERROR) {
791 p->setNotifyCallback(cookie, notifyFunc);
792 } else {
793 p.clear();
794 }
795 }
796 if (p == NULL) {
797 LOGE("Failed to create player object");
798 }
799 return p;
800}
801
802sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
803{
804 // determine if we have the right player type
805 sp<MediaPlayerBase> p = mPlayer;
806 if ((p != NULL) && (p->playerType() != playerType)) {
807 LOGV("delete player");
808 p.clear();
809 }
810 if (p == NULL) {
811 p = android::createPlayer(playerType, this, notify);
812 }
813 return p;
814}
815
Andreas Huber25643002010-01-28 11:19:57 -0800816status_t MediaPlayerService::Client::setDataSource(
817 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818{
819 LOGV("setDataSource(%s)", url);
820 if (url == NULL)
821 return UNKNOWN_ERROR;
822
823 if (strncmp(url, "content://", 10) == 0) {
824 // get a filedescriptor for the content Uri and
825 // pass it to the setDataSource(fd) method
826
827 String16 url16(url);
828 int fd = android::openContentProviderFile(url16);
829 if (fd < 0)
830 {
831 LOGE("Couldn't open fd for %s", url);
832 return UNKNOWN_ERROR;
833 }
834 setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
835 close(fd);
836 return mStatus;
837 } else {
838 player_type playerType = getPlayerType(url);
839 LOGV("player type = %d", playerType);
840
841 // create the right type of player
842 sp<MediaPlayerBase> p = createPlayer(playerType);
843 if (p == NULL) return NO_INIT;
844
845 if (!p->hardwareOutput()) {
Eric Laurent619346f2010-06-21 09:27:30 -0700846 mAudioOutput = new AudioOutput(mAudioSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
848 }
849
850 // now set data source
851 LOGV(" setDataSource");
Andreas Huber25643002010-01-28 11:19:57 -0800852 mStatus = p->setDataSource(url, headers);
Nicolas Catania8f5fcab2009-07-13 14:37:49 -0700853 if (mStatus == NO_ERROR) {
854 mPlayer = p;
855 } else {
856 LOGE(" error: %d", mStatus);
857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 return mStatus;
859 }
860}
861
862status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
863{
864 LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
865 struct stat sb;
866 int ret = fstat(fd, &sb);
867 if (ret != 0) {
868 LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
869 return UNKNOWN_ERROR;
870 }
871
872 LOGV("st_dev = %llu", sb.st_dev);
873 LOGV("st_mode = %u", sb.st_mode);
874 LOGV("st_uid = %lu", sb.st_uid);
875 LOGV("st_gid = %lu", sb.st_gid);
876 LOGV("st_size = %llu", sb.st_size);
877
878 if (offset >= sb.st_size) {
879 LOGE("offset error");
880 ::close(fd);
881 return UNKNOWN_ERROR;
882 }
883 if (offset + length > sb.st_size) {
884 length = sb.st_size - offset;
885 LOGV("calculated length = %lld", length);
886 }
887
888 player_type playerType = getPlayerType(fd, offset, length);
889 LOGV("player type = %d", playerType);
890
891 // create the right type of player
892 sp<MediaPlayerBase> p = createPlayer(playerType);
893 if (p == NULL) return NO_INIT;
894
895 if (!p->hardwareOutput()) {
Eric Laurent619346f2010-06-21 09:27:30 -0700896 mAudioOutput = new AudioOutput(mAudioSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
898 }
899
900 // now set data source
901 mStatus = p->setDataSource(fd, offset, length);
902 if (mStatus == NO_ERROR) mPlayer = p;
903 return mStatus;
904}
905
Andreas Huber52b52cd2010-11-23 11:41:34 -0800906status_t MediaPlayerService::Client::setDataSource(
907 const sp<IStreamSource> &source) {
908 // create the right type of player
Andreas Hubera1587462010-12-15 15:17:42 -0800909 sp<MediaPlayerBase> p = createPlayer(NU_PLAYER);
Andreas Huber52b52cd2010-11-23 11:41:34 -0800910
911 if (p == NULL) {
912 return NO_INIT;
913 }
914
915 if (!p->hardwareOutput()) {
916 mAudioOutput = new AudioOutput(mAudioSessionId);
917 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
918 }
919
920 // now set data source
921 mStatus = p->setDataSource(source);
922
923 if (mStatus == OK) {
924 mPlayer = p;
925 }
926
927 return mStatus;
928}
929
Andreas Hubere3c01832010-08-16 08:49:37 -0700930status_t MediaPlayerService::Client::setVideoSurface(const sp<Surface>& surface)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931{
932 LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get());
933 sp<MediaPlayerBase> p = getPlayer();
934 if (p == 0) return UNKNOWN_ERROR;
935 return p->setVideoSurface(surface);
936}
937
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700938status_t MediaPlayerService::Client::invoke(const Parcel& request,
939 Parcel *reply)
940{
941 sp<MediaPlayerBase> p = getPlayer();
942 if (p == NULL) return UNKNOWN_ERROR;
943 return p->invoke(request, reply);
944}
945
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700946// This call doesn't need to access the native player.
947status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
948{
949 status_t status;
nikobc726922009-07-20 15:07:26 -0700950 media::Metadata::Filter allow, drop;
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700951
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700952 if (unmarshallFilter(filter, &allow, &status) &&
953 unmarshallFilter(filter, &drop, &status)) {
954 Mutex::Autolock lock(mLock);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700955
956 mMetadataAllow = allow;
957 mMetadataDrop = drop;
958 }
959 return status;
960}
961
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700962status_t MediaPlayerService::Client::getMetadata(
963 bool update_only, bool apply_filter, Parcel *reply)
Nicolas Catania5d55c712009-07-09 09:21:33 -0700964{
nikobc726922009-07-20 15:07:26 -0700965 sp<MediaPlayerBase> player = getPlayer();
966 if (player == 0) return UNKNOWN_ERROR;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700967
niko89948372009-07-16 16:39:53 -0700968 status_t status;
969 // Placeholder for the return code, updated by the caller.
970 reply->writeInt32(-1);
971
nikobc726922009-07-20 15:07:26 -0700972 media::Metadata::Filter ids;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700973
974 // We don't block notifications while we fetch the data. We clear
975 // mMetadataUpdated first so we don't lose notifications happening
976 // during the rest of this call.
977 {
978 Mutex::Autolock lock(mLock);
979 if (update_only) {
niko89948372009-07-16 16:39:53 -0700980 ids = mMetadataUpdated;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700981 }
982 mMetadataUpdated.clear();
983 }
Nicolas Catania5d55c712009-07-09 09:21:33 -0700984
nikobc726922009-07-20 15:07:26 -0700985 media::Metadata metadata(reply);
Nicolas Catania4df8b2c2009-07-10 13:53:06 -0700986
nikobc726922009-07-20 15:07:26 -0700987 metadata.appendHeader();
988 status = player->getMetadata(ids, reply);
niko89948372009-07-16 16:39:53 -0700989
990 if (status != OK) {
nikobc726922009-07-20 15:07:26 -0700991 metadata.resetParcel();
niko89948372009-07-16 16:39:53 -0700992 LOGE("getMetadata failed %d", status);
993 return status;
994 }
995
996 // FIXME: Implement filtering on the result. Not critical since
997 // filtering takes place on the update notifications already. This
998 // would be when all the metadata are fetch and a filter is set.
999
niko89948372009-07-16 16:39:53 -07001000 // Everything is fine, update the metadata length.
nikobc726922009-07-20 15:07:26 -07001001 metadata.updateLength();
niko89948372009-07-16 16:39:53 -07001002 return OK;
Nicolas Catania5d55c712009-07-09 09:21:33 -07001003}
1004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005status_t MediaPlayerService::Client::prepareAsync()
1006{
1007 LOGV("[%d] prepareAsync", mConnId);
1008 sp<MediaPlayerBase> p = getPlayer();
1009 if (p == 0) return UNKNOWN_ERROR;
1010 status_t ret = p->prepareAsync();
1011#if CALLBACK_ANTAGONIZER
1012 LOGD("start Antagonizer");
1013 if (ret == NO_ERROR) mAntagonizer->start();
1014#endif
1015 return ret;
1016}
1017
1018status_t MediaPlayerService::Client::start()
1019{
1020 LOGV("[%d] start", mConnId);
1021 sp<MediaPlayerBase> p = getPlayer();
1022 if (p == 0) return UNKNOWN_ERROR;
1023 p->setLooping(mLoop);
1024 return p->start();
1025}
1026
1027status_t MediaPlayerService::Client::stop()
1028{
1029 LOGV("[%d] stop", mConnId);
1030 sp<MediaPlayerBase> p = getPlayer();
1031 if (p == 0) return UNKNOWN_ERROR;
1032 return p->stop();
1033}
1034
1035status_t MediaPlayerService::Client::pause()
1036{
1037 LOGV("[%d] pause", mConnId);
1038 sp<MediaPlayerBase> p = getPlayer();
1039 if (p == 0) return UNKNOWN_ERROR;
1040 return p->pause();
1041}
1042
1043status_t MediaPlayerService::Client::isPlaying(bool* state)
1044{
1045 *state = false;
1046 sp<MediaPlayerBase> p = getPlayer();
1047 if (p == 0) return UNKNOWN_ERROR;
1048 *state = p->isPlaying();
1049 LOGV("[%d] isPlaying: %d", mConnId, *state);
1050 return NO_ERROR;
1051}
1052
1053status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
1054{
1055 LOGV("getCurrentPosition");
1056 sp<MediaPlayerBase> p = getPlayer();
1057 if (p == 0) return UNKNOWN_ERROR;
1058 status_t ret = p->getCurrentPosition(msec);
1059 if (ret == NO_ERROR) {
1060 LOGV("[%d] getCurrentPosition = %d", mConnId, *msec);
1061 } else {
1062 LOGE("getCurrentPosition returned %d", ret);
1063 }
1064 return ret;
1065}
1066
1067status_t MediaPlayerService::Client::getDuration(int *msec)
1068{
1069 LOGV("getDuration");
1070 sp<MediaPlayerBase> p = getPlayer();
1071 if (p == 0) return UNKNOWN_ERROR;
1072 status_t ret = p->getDuration(msec);
1073 if (ret == NO_ERROR) {
1074 LOGV("[%d] getDuration = %d", mConnId, *msec);
1075 } else {
1076 LOGE("getDuration returned %d", ret);
1077 }
1078 return ret;
1079}
1080
1081status_t MediaPlayerService::Client::seekTo(int msec)
1082{
1083 LOGV("[%d] seekTo(%d)", mConnId, msec);
1084 sp<MediaPlayerBase> p = getPlayer();
1085 if (p == 0) return UNKNOWN_ERROR;
1086 return p->seekTo(msec);
1087}
1088
1089status_t MediaPlayerService::Client::reset()
1090{
1091 LOGV("[%d] reset", mConnId);
1092 sp<MediaPlayerBase> p = getPlayer();
1093 if (p == 0) return UNKNOWN_ERROR;
1094 return p->reset();
1095}
1096
1097status_t MediaPlayerService::Client::setAudioStreamType(int type)
1098{
1099 LOGV("[%d] setAudioStreamType(%d)", mConnId, type);
1100 // TODO: for hardware output, call player instead
1101 Mutex::Autolock l(mLock);
1102 if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
1103 return NO_ERROR;
1104}
1105
1106status_t MediaPlayerService::Client::setLooping(int loop)
1107{
1108 LOGV("[%d] setLooping(%d)", mConnId, loop);
1109 mLoop = loop;
1110 sp<MediaPlayerBase> p = getPlayer();
1111 if (p != 0) return p->setLooping(loop);
1112 return NO_ERROR;
1113}
1114
1115status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
1116{
1117 LOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
1118 // TODO: for hardware output, call player instead
1119 Mutex::Autolock l(mLock);
1120 if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
1121 return NO_ERROR;
1122}
1123
Eric Laurent7070b362010-07-16 07:43:46 -07001124status_t MediaPlayerService::Client::setAuxEffectSendLevel(float level)
1125{
1126 LOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
1127 Mutex::Autolock l(mLock);
1128 if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
1129 return NO_ERROR;
1130}
1131
1132status_t MediaPlayerService::Client::attachAuxEffect(int effectId)
1133{
1134 LOGV("[%d] attachAuxEffect(%d)", mConnId, effectId);
1135 Mutex::Autolock l(mLock);
1136 if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId);
1137 return NO_ERROR;
1138}
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
1141{
1142 Client* client = static_cast<Client*>(cookie);
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001143
1144 if (MEDIA_INFO == msg &&
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001145 MEDIA_INFO_METADATA_UPDATE == ext1) {
nikobc726922009-07-20 15:07:26 -07001146 const media::Metadata::Type metadata_type = ext2;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001147
1148 if(client->shouldDropMetadata(metadata_type)) {
1149 return;
1150 }
1151
1152 // Update the list of metadata that have changed. getMetadata
1153 // also access mMetadataUpdated and clears it.
1154 client->addNewMetadataUpdate(metadata_type);
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
1157 client->mClient->notify(msg, ext1, ext2);
1158}
1159
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001160
nikobc726922009-07-20 15:07:26 -07001161bool MediaPlayerService::Client::shouldDropMetadata(media::Metadata::Type code) const
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001162{
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001163 Mutex::Autolock lock(mLock);
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001164
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001165 if (findMetadata(mMetadataDrop, code)) {
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001166 return true;
1167 }
1168
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001169 if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001170 return false;
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001171 } else {
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001172 return true;
1173 }
1174}
1175
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001176
nikobc726922009-07-20 15:07:26 -07001177void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
Nicolas Catania4df8b2c2009-07-10 13:53:06 -07001178 Mutex::Autolock lock(mLock);
1179 if (mMetadataUpdated.indexOf(metadata_type) < 0) {
1180 mMetadataUpdated.add(metadata_type);
1181 }
1182}
1183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184#if CALLBACK_ANTAGONIZER
1185const int Antagonizer::interval = 10000; // 10 msecs
1186
1187Antagonizer::Antagonizer(notify_callback_f cb, void* client) :
1188 mExit(false), mActive(false), mClient(client), mCb(cb)
1189{
1190 createThread(callbackThread, this);
1191}
1192
1193void Antagonizer::kill()
1194{
1195 Mutex::Autolock _l(mLock);
1196 mActive = false;
1197 mExit = true;
1198 mCondition.wait(mLock);
1199}
1200
1201int Antagonizer::callbackThread(void* user)
1202{
1203 LOGD("Antagonizer started");
1204 Antagonizer* p = reinterpret_cast<Antagonizer*>(user);
1205 while (!p->mExit) {
1206 if (p->mActive) {
1207 LOGV("send event");
1208 p->mCb(p->mClient, 0, 0, 0);
1209 }
1210 usleep(interval);
1211 }
1212 Mutex::Autolock _l(p->mLock);
1213 p->mCondition.signal();
1214 LOGD("Antagonizer stopped");
1215 return 0;
1216}
1217#endif
1218
1219static size_t kDefaultHeapSize = 1024 * 1024; // 1MB
1220
1221sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
1222{
1223 LOGV("decode(%s)", url);
1224 sp<MemoryBase> mem;
1225 sp<MediaPlayerBase> player;
1226
1227 // Protect our precious, precious DRMd ringtones by only allowing
1228 // decoding of http, but not filesystem paths or content Uris.
1229 // If the application wants to decode those, it should open a
1230 // filedescriptor for them and use that.
1231 if (url != NULL && strncmp(url, "http://", 7) != 0) {
1232 LOGD("Can't decode %s by path, use filedescriptor instead", url);
1233 return mem;
1234 }
1235
1236 player_type playerType = getPlayerType(url);
1237 LOGV("player type = %d", playerType);
1238
1239 // create the right type of player
1240 sp<AudioCache> cache = new AudioCache(url);
1241 player = android::createPlayer(playerType, cache.get(), cache->notify);
1242 if (player == NULL) goto Exit;
1243 if (player->hardwareOutput()) goto Exit;
1244
1245 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1246
1247 // set data source
1248 if (player->setDataSource(url) != NO_ERROR) goto Exit;
1249
1250 LOGV("prepare");
1251 player->prepareAsync();
1252
1253 LOGV("wait for prepare");
1254 if (cache->wait() != NO_ERROR) goto Exit;
1255
1256 LOGV("start");
1257 player->start();
1258
1259 LOGV("wait for playback complete");
1260 if (cache->wait() != NO_ERROR) goto Exit;
1261
1262 mem = new MemoryBase(cache->getHeap(), 0, cache->size());
1263 *pSampleRate = cache->sampleRate();
1264 *pNumChannels = cache->channelCount();
1265 *pFormat = cache->format();
1266 LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
1267
1268Exit:
1269 if (player != 0) player->reset();
1270 return mem;
1271}
1272
1273sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
1274{
1275 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
1276 sp<MemoryBase> mem;
1277 sp<MediaPlayerBase> player;
1278
1279 player_type playerType = getPlayerType(fd, offset, length);
1280 LOGV("player type = %d", playerType);
1281
1282 // create the right type of player
1283 sp<AudioCache> cache = new AudioCache("decode_fd");
1284 player = android::createPlayer(playerType, cache.get(), cache->notify);
1285 if (player == NULL) goto Exit;
1286 if (player->hardwareOutput()) goto Exit;
1287
1288 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1289
1290 // set data source
1291 if (player->setDataSource(fd, offset, length) != NO_ERROR) goto Exit;
1292
1293 LOGV("prepare");
1294 player->prepareAsync();
1295
1296 LOGV("wait for prepare");
1297 if (cache->wait() != NO_ERROR) goto Exit;
1298
1299 LOGV("start");
1300 player->start();
1301
1302 LOGV("wait for playback complete");
1303 if (cache->wait() != NO_ERROR) goto Exit;
1304
1305 mem = new MemoryBase(cache->getHeap(), 0, cache->size());
1306 *pSampleRate = cache->sampleRate();
1307 *pNumChannels = cache->channelCount();
1308 *pFormat = cache->format();
1309 LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
1310
1311Exit:
1312 if (player != 0) player->reset();
1313 ::close(fd);
1314 return mem;
1315}
1316
Marco Nelissenc39d2e32009-09-20 10:42:13 -07001317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318#undef LOG_TAG
1319#define LOG_TAG "AudioSink"
Eric Laurent619346f2010-06-21 09:27:30 -07001320MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
Andreas Hubere46b7be2009-07-14 16:56:47 -07001321 : mCallback(NULL),
Eric Laurent619346f2010-06-21 09:27:30 -07001322 mCallbackCookie(NULL),
1323 mSessionId(sessionId) {
1324 LOGV("AudioOutput(%d)", sessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 mTrack = 0;
1326 mStreamType = AudioSystem::MUSIC;
1327 mLeftVolume = 1.0;
1328 mRightVolume = 1.0;
1329 mLatency = 0;
1330 mMsecsPerFrame = 0;
Eric Laurent7070b362010-07-16 07:43:46 -07001331 mAuxEffectId = 0;
1332 mSendLevel = 0.0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 setMinBufferCount();
1334}
1335
1336MediaPlayerService::AudioOutput::~AudioOutput()
1337{
1338 close();
1339}
1340
1341void MediaPlayerService::AudioOutput::setMinBufferCount()
1342{
1343 char value[PROPERTY_VALUE_MAX];
1344 if (property_get("ro.kernel.qemu", value, 0)) {
1345 mIsOnEmulator = true;
1346 mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
1347 }
1348}
1349
1350bool MediaPlayerService::AudioOutput::isOnEmulator()
1351{
1352 setMinBufferCount();
1353 return mIsOnEmulator;
1354}
1355
1356int MediaPlayerService::AudioOutput::getMinBufferCount()
1357{
1358 setMinBufferCount();
1359 return mMinBufferCount;
1360}
1361
1362ssize_t MediaPlayerService::AudioOutput::bufferSize() const
1363{
1364 if (mTrack == 0) return NO_INIT;
1365 return mTrack->frameCount() * frameSize();
1366}
1367
1368ssize_t MediaPlayerService::AudioOutput::frameCount() const
1369{
1370 if (mTrack == 0) return NO_INIT;
1371 return mTrack->frameCount();
1372}
1373
1374ssize_t MediaPlayerService::AudioOutput::channelCount() const
1375{
1376 if (mTrack == 0) return NO_INIT;
1377 return mTrack->channelCount();
1378}
1379
1380ssize_t MediaPlayerService::AudioOutput::frameSize() const
1381{
1382 if (mTrack == 0) return NO_INIT;
1383 return mTrack->frameSize();
1384}
1385
1386uint32_t MediaPlayerService::AudioOutput::latency () const
1387{
1388 return mLatency;
1389}
1390
1391float MediaPlayerService::AudioOutput::msecsPerFrame() const
1392{
1393 return mMsecsPerFrame;
1394}
1395
Eric Laurent0986e792010-01-19 17:37:09 -08001396status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position)
1397{
1398 if (mTrack == 0) return NO_INIT;
1399 return mTrack->getPosition(position);
1400}
1401
Andreas Hubere46b7be2009-07-14 16:56:47 -07001402status_t MediaPlayerService::AudioOutput::open(
1403 uint32_t sampleRate, int channelCount, int format, int bufferCount,
1404 AudioCallback cb, void *cookie)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405{
Andreas Hubere46b7be2009-07-14 16:56:47 -07001406 mCallback = cb;
1407 mCallbackCookie = cookie;
1408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 // Check argument "bufferCount" against the mininum buffer count
1410 if (bufferCount < mMinBufferCount) {
1411 LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
1412 bufferCount = mMinBufferCount;
1413
1414 }
Eric Laurent619346f2010-06-21 09:27:30 -07001415 LOGV("open(%u, %d, %d, %d, %d)", sampleRate, channelCount, format, bufferCount,mSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 if (mTrack) close();
1417 int afSampleRate;
1418 int afFrameCount;
1419 int frameCount;
1420
1421 if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
1422 return NO_INIT;
1423 }
1424 if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
1425 return NO_INIT;
1426 }
1427
1428 frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001429
1430 AudioTrack *t;
1431 if (mCallback != NULL) {
1432 t = new AudioTrack(
Eric Laurenta553c252009-07-17 12:17:14 -07001433 mStreamType,
1434 sampleRate,
1435 format,
1436 (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
1437 frameCount,
1438 0 /* flags */,
1439 CallbackWrapper,
Eric Laurent619346f2010-06-21 09:27:30 -07001440 this,
1441 0,
1442 mSessionId);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001443 } else {
1444 t = new AudioTrack(
Eric Laurenta553c252009-07-17 12:17:14 -07001445 mStreamType,
1446 sampleRate,
1447 format,
1448 (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
Eric Laurent619346f2010-06-21 09:27:30 -07001449 frameCount,
1450 0,
1451 NULL,
1452 NULL,
1453 0,
1454 mSessionId);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001455 }
1456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 if ((t == 0) || (t->initCheck() != NO_ERROR)) {
1458 LOGE("Unable to create audio track");
1459 delete t;
1460 return NO_INIT;
1461 }
1462
1463 LOGV("setVolume");
1464 t->setVolume(mLeftVolume, mRightVolume);
Eric Laurent7070b362010-07-16 07:43:46 -07001465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Dave Sparksb904c2a2009-12-03 10:13:32 -08001467 mLatency = t->latency();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 mTrack = t;
Eric Laurent7070b362010-07-16 07:43:46 -07001469
1470 t->setAuxEffectSendLevel(mSendLevel);
1471 return t->attachAuxEffect(mAuxEffectId);;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472}
1473
1474void MediaPlayerService::AudioOutput::start()
1475{
1476 LOGV("start");
1477 if (mTrack) {
1478 mTrack->setVolume(mLeftVolume, mRightVolume);
Eric Laurent7070b362010-07-16 07:43:46 -07001479 mTrack->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 mTrack->start();
1481 }
1482}
1483
Marco Nelissene274db12010-01-12 09:23:54 -08001484
1485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
1487{
Andreas Hubere46b7be2009-07-14 16:56:47 -07001488 LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
1489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 //LOGV("write(%p, %u)", buffer, size);
Marco Nelissenc39d2e32009-09-20 10:42:13 -07001491 if (mTrack) {
Marco Nelissenc39d2e32009-09-20 10:42:13 -07001492 ssize_t ret = mTrack->write(buffer, size);
Marco Nelissenc39d2e32009-09-20 10:42:13 -07001493 return ret;
1494 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 return NO_INIT;
1496}
1497
1498void MediaPlayerService::AudioOutput::stop()
1499{
1500 LOGV("stop");
1501 if (mTrack) mTrack->stop();
1502}
1503
1504void MediaPlayerService::AudioOutput::flush()
1505{
1506 LOGV("flush");
1507 if (mTrack) mTrack->flush();
1508}
1509
1510void MediaPlayerService::AudioOutput::pause()
1511{
1512 LOGV("pause");
1513 if (mTrack) mTrack->pause();
1514}
1515
1516void MediaPlayerService::AudioOutput::close()
1517{
1518 LOGV("close");
1519 delete mTrack;
1520 mTrack = 0;
1521}
1522
1523void MediaPlayerService::AudioOutput::setVolume(float left, float right)
1524{
1525 LOGV("setVolume(%f, %f)", left, right);
1526 mLeftVolume = left;
1527 mRightVolume = right;
1528 if (mTrack) {
1529 mTrack->setVolume(left, right);
1530 }
1531}
1532
Eric Laurent7070b362010-07-16 07:43:46 -07001533status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
1534{
1535 LOGV("setAuxEffectSendLevel(%f)", level);
1536 mSendLevel = level;
1537 if (mTrack) {
1538 return mTrack->setAuxEffectSendLevel(level);
1539 }
1540 return NO_ERROR;
1541}
1542
1543status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
1544{
1545 LOGV("attachAuxEffect(%d)", effectId);
1546 mAuxEffectId = effectId;
1547 if (mTrack) {
1548 return mTrack->attachAuxEffect(effectId);
1549 }
1550 return NO_ERROR;
1551}
1552
Andreas Hubere46b7be2009-07-14 16:56:47 -07001553// static
1554void MediaPlayerService::AudioOutput::CallbackWrapper(
1555 int event, void *cookie, void *info) {
Marco Nelissene274db12010-01-12 09:23:54 -08001556 //LOGV("callbackwrapper");
Andreas Hubere46b7be2009-07-14 16:56:47 -07001557 if (event != AudioTrack::EVENT_MORE_DATA) {
1558 return;
1559 }
1560
1561 AudioOutput *me = (AudioOutput *)cookie;
1562 AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
1563
Andreas Huber6ed937e2010-02-09 16:59:18 -08001564 size_t actualSize = (*me->mCallback)(
Andreas Hubere46b7be2009-07-14 16:56:47 -07001565 me, buffer->raw, buffer->size, me->mCallbackCookie);
Andreas Huber6ed937e2010-02-09 16:59:18 -08001566
Andreas Huber406a18b2010-02-18 16:45:13 -08001567 buffer->size = actualSize;
1568
Andreas Hubere46b7be2009-07-14 16:56:47 -07001569}
1570
Eric Laurentb3bdf3f2010-10-07 18:23:03 -07001571int MediaPlayerService::AudioOutput::getSessionId()
1572{
1573 return mSessionId;
1574}
1575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576#undef LOG_TAG
1577#define LOG_TAG "AudioCache"
1578MediaPlayerService::AudioCache::AudioCache(const char* name) :
1579 mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
1580 mError(NO_ERROR), mCommandComplete(false)
1581{
1582 // create ashmem heap
1583 mHeap = new MemoryHeapBase(kDefaultHeapSize, 0, name);
1584}
1585
1586uint32_t MediaPlayerService::AudioCache::latency () const
1587{
1588 return 0;
1589}
1590
1591float MediaPlayerService::AudioCache::msecsPerFrame() const
1592{
1593 return mMsecsPerFrame;
1594}
1595
Eric Laurent0986e792010-01-19 17:37:09 -08001596status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position)
1597{
1598 if (position == 0) return BAD_VALUE;
1599 *position = mSize;
1600 return NO_ERROR;
1601}
1602
Andreas Huber6ed937e2010-02-09 16:59:18 -08001603////////////////////////////////////////////////////////////////////////////////
1604
1605struct CallbackThread : public Thread {
1606 CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink,
1607 MediaPlayerBase::AudioSink::AudioCallback cb,
1608 void *cookie);
1609
1610protected:
1611 virtual ~CallbackThread();
1612
1613 virtual bool threadLoop();
1614
1615private:
1616 wp<MediaPlayerBase::AudioSink> mSink;
1617 MediaPlayerBase::AudioSink::AudioCallback mCallback;
1618 void *mCookie;
1619 void *mBuffer;
1620 size_t mBufferSize;
1621
1622 CallbackThread(const CallbackThread &);
1623 CallbackThread &operator=(const CallbackThread &);
1624};
1625
1626CallbackThread::CallbackThread(
1627 const wp<MediaPlayerBase::AudioSink> &sink,
1628 MediaPlayerBase::AudioSink::AudioCallback cb,
1629 void *cookie)
1630 : mSink(sink),
1631 mCallback(cb),
1632 mCookie(cookie),
1633 mBuffer(NULL),
1634 mBufferSize(0) {
1635}
1636
1637CallbackThread::~CallbackThread() {
1638 if (mBuffer) {
1639 free(mBuffer);
1640 mBuffer = NULL;
1641 }
1642}
1643
1644bool CallbackThread::threadLoop() {
1645 sp<MediaPlayerBase::AudioSink> sink = mSink.promote();
1646 if (sink == NULL) {
1647 return false;
1648 }
1649
1650 if (mBuffer == NULL) {
1651 mBufferSize = sink->bufferSize();
1652 mBuffer = malloc(mBufferSize);
1653 }
1654
1655 size_t actualSize =
1656 (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie);
1657
1658 if (actualSize > 0) {
1659 sink->write(mBuffer, actualSize);
1660 }
1661
1662 return true;
1663}
1664
1665////////////////////////////////////////////////////////////////////////////////
1666
Andreas Hubere46b7be2009-07-14 16:56:47 -07001667status_t MediaPlayerService::AudioCache::open(
1668 uint32_t sampleRate, int channelCount, int format, int bufferCount,
1669 AudioCallback cb, void *cookie)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670{
Dave Sparks14f89402009-12-09 20:20:26 -08001671 LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
Dave Sparks14f89402009-12-09 20:20:26 -08001672 if (mHeap->getHeapID() < 0) {
1673 return NO_INIT;
1674 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 mSampleRate = sampleRate;
1677 mChannelCount = (uint16_t)channelCount;
1678 mFormat = (uint16_t)format;
1679 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Andreas Huber6ed937e2010-02-09 16:59:18 -08001680
1681 if (cb != NULL) {
1682 mCallbackThread = new CallbackThread(this, cb, cookie);
1683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 return NO_ERROR;
1685}
1686
Andreas Huber6ed937e2010-02-09 16:59:18 -08001687void MediaPlayerService::AudioCache::start() {
1688 if (mCallbackThread != NULL) {
1689 mCallbackThread->run("AudioCache callback");
1690 }
1691}
1692
1693void MediaPlayerService::AudioCache::stop() {
1694 if (mCallbackThread != NULL) {
1695 mCallbackThread->requestExitAndWait();
1696 }
1697}
1698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
1700{
1701 LOGV("write(%p, %u)", buffer, size);
1702 if ((buffer == 0) || (size == 0)) return size;
1703
1704 uint8_t* p = static_cast<uint8_t*>(mHeap->getBase());
1705 if (p == NULL) return NO_INIT;
1706 p += mSize;
1707 LOGV("memcpy(%p, %p, %u)", p, buffer, size);
1708 if (mSize + size > mHeap->getSize()) {
1709 LOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
1710 size = mHeap->getSize() - mSize;
1711 }
1712 memcpy(p, buffer, size);
1713 mSize += size;
1714 return size;
1715}
1716
1717// call with lock held
1718status_t MediaPlayerService::AudioCache::wait()
1719{
1720 Mutex::Autolock lock(mLock);
Dave Sparks16433e22010-03-01 19:29:58 -08001721 while (!mCommandComplete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 mSignal.wait(mLock);
1723 }
1724 mCommandComplete = false;
1725
1726 if (mError == NO_ERROR) {
1727 LOGV("wait - success");
1728 } else {
1729 LOGV("wait - error");
1730 }
1731 return mError;
1732}
1733
1734void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int ext2)
1735{
1736 LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
1737 AudioCache* p = static_cast<AudioCache*>(cookie);
1738
1739 // ignore buffering messages
Dave Sparks14f89402009-12-09 20:20:26 -08001740 switch (msg)
1741 {
1742 case MEDIA_ERROR:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 LOGE("Error %d, %d occurred", ext1, ext2);
1744 p->mError = ext1;
Dave Sparks14f89402009-12-09 20:20:26 -08001745 break;
1746 case MEDIA_PREPARED:
1747 LOGV("prepared");
1748 break;
1749 case MEDIA_PLAYBACK_COMPLETE:
1750 LOGV("playback complete");
1751 break;
1752 default:
1753 LOGV("ignored");
1754 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756
1757 // wake up thread
Dave Sparks6c26fe42010-03-02 12:56:37 -08001758 Mutex::Autolock lock(p->mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 p->mCommandComplete = true;
1760 p->mSignal.signal();
1761}
1762
Eric Laurentb3bdf3f2010-10-07 18:23:03 -07001763int MediaPlayerService::AudioCache::getSessionId()
1764{
1765 return 0;
1766}
1767
Gloria Wangd211f412011-02-19 18:37:57 -08001768void MediaPlayerService::addBatteryData(uint32_t params)
1769{
1770 Mutex::Autolock lock(mLock);
1771 int uid = IPCThreadState::self()->getCallingUid();
1772 if (uid == AID_MEDIA) {
1773 return;
1774 }
1775 int index = mBatteryData.indexOfKey(uid);
1776 int32_t time = systemTime() / 1000000L;
1777
1778 if (index < 0) { // create a new entry for this UID
1779 BatteryUsageInfo info;
1780 info.audioTotalTime = 0;
1781 info.videoTotalTime = 0;
1782 info.audioLastTime = 0;
1783 info.videoLastTime = 0;
1784 info.refCount = 0;
1785
1786 mBatteryData.add(uid, info);
1787 }
1788
1789 BatteryUsageInfo &info = mBatteryData.editValueFor(uid);
1790
1791 if (params & kBatteryDataCodecStarted) {
1792 if (params & kBatteryDataTrackAudio) {
1793 info.audioLastTime -= time;
1794 info.refCount ++;
1795 }
1796 if (params & kBatteryDataTrackVideo) {
1797 info.videoLastTime -= time;
1798 info.refCount ++;
1799 }
1800 } else {
1801 if (info.refCount == 0) {
1802 LOGW("Battery track warning: refCount is already 0");
1803 return;
1804 } else if (info.refCount < 0) {
1805 LOGE("Battery track error: refCount < 0");
1806 mBatteryData.removeItem(uid);
1807 return;
1808 }
1809
1810 if (params & kBatteryDataTrackAudio) {
1811 info.audioLastTime += time;
1812 info.refCount --;
1813 }
1814 if (params & kBatteryDataTrackVideo) {
1815 info.videoLastTime += time;
1816 info.refCount --;
1817 }
1818
1819 // no stream is being played by this UID
1820 if (info.refCount == 0) {
1821 info.audioTotalTime += info.audioLastTime;
1822 info.audioLastTime = 0;
1823 info.videoTotalTime += info.videoLastTime;
1824 info.videoLastTime = 0;
1825 }
1826 }
1827}
1828
1829status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
1830 Mutex::Autolock lock(mLock);
1831 BatteryUsageInfo info;
1832 int size = mBatteryData.size();
1833
1834 reply->writeInt32(size);
1835 int i = 0;
1836
1837 while (i < size) {
1838 info = mBatteryData.valueAt(i);
1839
1840 reply->writeInt32(mBatteryData.keyAt(i)); //UID
1841 reply->writeInt32(info.audioTotalTime);
1842 reply->writeInt32(info.videoTotalTime);
1843
1844 info.audioTotalTime = 0;
1845 info.videoTotalTime = 0;
1846
1847 // remove the UID entry where no stream is being played
1848 if (info.refCount <= 0) {
1849 mBatteryData.removeItemsAt(i);
1850 size --;
1851 i --;
1852 }
1853 i++;
1854 }
1855 return NO_ERROR;
1856}
nikobc726922009-07-20 15:07:26 -07001857} // namespace android