blob: ec6188f01ee2065abcca51f85f80e6494902c0fd [file] [log] [blame]
The Android Open Source Project89fa4ad2009-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 Wang7cf180c2011-02-19 18:37:57 -080026#include <sys/time.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080027#include <dirent.h>
28#include <unistd.h>
29
30#include <string.h>
Mathias Agopian6f74b0c2009-06-03 17:32:49 -070031
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080032#include <cutils/atomic.h>
Nicolas Catania14d27472009-07-13 14:37:49 -070033#include <cutils/properties.h> // for property_get
Mathias Agopian6f74b0c2009-06-03 17:32:49 -070034
35#include <utils/misc.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080036
37#include <android_runtime/ActivityManager.h>
Mathias Agopian6f74b0c2009-06-03 17:32:49 -070038
Mathias Agopian75624082009-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 Catania1d187f12009-05-12 23:25:55 -070043#include <utils/Errors.h> // for status_t
44#include <utils/String8.h>
Marco Nelissen10dbb8e2009-09-20 10:42:13 -070045#include <utils/SystemClock.h>
Nicolas Catania1d187f12009-05-12 23:25:55 -070046#include <utils/Vector.h>
The Android Open Source Project89fa4ad2009-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>
nikoa64c8c72009-07-20 15:07:26 -070052#include <media/Metadata.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080053#include <media/AudioTrack.h>
54
Gloria Wang7cf180c2011-02-19 18:37:57 -080055#include <private/android_filesystem_config.h>
56
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080057#include "MediaRecorderClient.h"
58#include "MediaPlayerService.h"
59#include "MetadataRetrieverClient.h"
60
61#include "MidiFile.h"
Nicolas Catania14d27472009-07-13 14:37:49 -070062#include "TestPlayerStub.h"
Andreas Huber20111aa2009-07-14 16:56:47 -070063#include "StagefrightPlayer.h"
Andreas Huberf9334412010-12-15 15:17:42 -080064#include "nuplayer/NuPlayerDriver.h"
Andreas Huber20111aa2009-07-14 16:56:47 -070065
Andreas Huber20111aa2009-07-14 16:56:47 -070066#include <OMX.h>
Nicolas Catania14d27472009-07-13 14:37:49 -070067
The Android Open Source Project89fa4ad2009-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 Cataniaa7e0e8b2009-07-08 08:57:42 -070080namespace {
nikoa64c8c72009-07-20 15:07:26 -070081using android::media::Metadata;
Nicolas Cataniaa7e0e8b2009-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 Cataniaa7e0e8b2009-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
nikoa64c8c72009-07-20 15:07:26 -070091// FIXME: Move all the metadata related function in the Metadata.cpp
nikod608a812009-07-16 16:39:53 -070092
Nicolas Cataniaa7e0e8b2009-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,
nikoa64c8c72009-07-20 15:07:26 -0700116 Metadata::Filter *filter,
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700117 status_t *status)
118{
Nicolas Catania48290382009-07-10 13:53:06 -0700119 int32_t val;
120 if (p.readInt32(&val) != OK)
Nicolas Cataniaa7e0e8b2009-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 Catania48290382009-07-10 13:53:06 -0700127 if( val > kMaxFilterSize || val < 0)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700128 {
Nicolas Catania48290382009-07-10 13:53:06 -0700129 LOGE("Invalid filter len %d", val);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700130 *status = BAD_VALUE;
131 return false;
132 }
133
Nicolas Catania48290382009-07-10 13:53:06 -0700134 const size_t num = val;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700135
136 filter->clear();
Nicolas Catania48290382009-07-10 13:53:06 -0700137 filter->setCapacity(num);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700138
nikoa64c8c72009-07-20 15:07:26 -0700139 size_t size = num * sizeof(Metadata::Type);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700140
Nicolas Catania48290382009-07-10 13:53:06 -0700141
142 if (p.dataAvail() < size)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700143 {
Nicolas Catania48290382009-07-10 13:53:06 -0700144 LOGE("Filter too short expected %d but got %d", size, p.dataAvail());
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700145 *status = NOT_ENOUGH_DATA;
146 return false;
147 }
148
nikoa64c8c72009-07-20 15:07:26 -0700149 const Metadata::Type *data =
150 static_cast<const Metadata::Type*>(p.readInplace(size));
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700151
Nicolas Catania48290382009-07-10 13:53:06 -0700152 if (NULL == data)
Nicolas Cataniaa7e0e8b2009-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 Catania48290382009-07-10 13:53:06 -0700162 for (size_t i = 0; i < num; ++i)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700163 {
Nicolas Catania48290382009-07-10 13:53:06 -0700164 filter->add(*data);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700165 ++data;
166 }
167 *status = OK;
168 return true;
169}
170
Nicolas Catania48290382009-07-10 13:53:06 -0700171// @param filter Of metadata type.
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700172// @param val To be searched.
173// @return true if a match was found.
nikoa64c8c72009-07-20 15:07:26 -0700174bool findMetadata(const Metadata::Filter& filter, const int32_t val)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700175{
176 // Deal with empty and ANY right away
177 if (filter.isEmpty()) return false;
nikoa64c8c72009-07-20 15:07:26 -0700178 if (filter[0] == Metadata::kAny) return true;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700179
Nicolas Catania48290382009-07-10 13:53:06 -0700180 return filter.indexOf(val) >= 0;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700181}
182
183} // anonymous namespace
184
185
The Android Open Source Project89fa4ad2009-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 Project89fa4ad2009-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 Project89fa4ad2009-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 Wangdac6a312009-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 Project89fa4ad2009-03-03 19:31:44 -0800230 LOGV("Create new media recorder client from pid %d", pid);
231 return recorder;
232}
233
Gloria Wangdac6a312009-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 Project89fa4ad2009-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 Huber2db84552010-01-28 11:19:57 -0800248sp<IMediaPlayer> MediaPlayerService::create(
249 pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
Eric Laurenta514bdb2010-06-21 09:27:30 -0700250 const KeyedVector<String8, String8> *headers, int audioSessionId)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800251{
252 int32_t connId = android_atomic_inc(&mNextConnId);
Eric Laurenta514bdb2010-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 Huber2db84552010-01-28 11:19:57 -0800256 if (NO_ERROR != c->setDataSource(url, headers))
The Android Open Source Project89fa4ad2009-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 Laurenta514bdb2010-06-21 09:27:30 -0700268 int fd, int64_t offset, int64_t length, int audioSessionId)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800269{
270 int32_t connId = android_atomic_inc(&mNextConnId);
Eric Laurenta514bdb2010-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 Project89fa4ad2009-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 Hubere2b10282010-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 Huber318ad9c2009-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 Huber20111aa2009-07-14 16:56:47 -0700313}
314
The Android Open Source Project89fa4ad2009-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 Laurent2beeb502010-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 Project89fa4ad2009-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 Huber1eea7f52009-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 Project89fa4ad2009-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 Huber1eea7f52009-10-27 15:50:04 -0700428 MyString8 result;
The Android Open Source Project89fa4ad2009-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 Dong1edee162010-02-25 10:06:32 -0800449 snprintf(buffer, SIZE, " Total memory %i\n", totalMemory);
450 result.append(buffer);
The Android Open Source Project89fa4ad2009-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 Dong1edee162010-02-25 10:06:32 -0800499 snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups);
The Android Open Source Project89fa4ad2009-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 Dongb9141222010-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 Wangdac6a312009-10-29 15:46:37 -0700547 }
548
The Android Open Source Project89fa4ad2009-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 Sparks02fa8342010-09-27 16:55:18 -0700555 if (strstr(buffer, " /mnt/sdcard/") ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800556 strstr(buffer, " /system/sounds/") ||
Dave Sparks02fa8342010-09-27 16:55:18 -0700557 strstr(buffer, " /data/") ||
The Android Open Source Project89fa4ad2009-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 Sparks02fa8342010-09-27 16:55:18 -0700591 if (strstr(linkto, "/mnt/sdcard/") == linkto ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800592 strstr(linkto, "/system/sounds/") == linkto ||
Dave Sparks02fa8342010-09-27 16:55:18 -0700593 strstr(linkto, "/data/") == linkto ||
The Android Open Source Project89fa4ad2009-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 Laurenta514bdb2010-06-21 09:27:30 -0700640 int32_t connId, const sp<IMediaPlayerClient>& client, int audioSessionId)
The Android Open Source Project89fa4ad2009-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 Laurenta514bdb2010-06-21 09:27:30 -0700649 mAudioSessionId = audioSessionId;
650
The Android Open Source Project89fa4ad2009-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 Sparks795fa582009-03-24 17:57:12 -0700676 mClient.clear();
Andreas Huber20111aa2009-07-14 16:56:47 -0700677
The Android Open Source Project89fa4ad2009-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 Huber47f59cf2009-08-07 09:30:32 -0700695static player_type getDefaultPlayerType() {
Andreas Huber608d77b2010-06-23 16:40:57 -0700696 return STAGEFRIGHT_PLAYER;
Andreas Huber47f59cf2009-08-07 09:30:32 -0700697}
698
James Dong148c1a22009-09-06 14:29:45 -0700699player_type getPlayerType(int fd, int64_t offset, int64_t length)
The Android Open Source Project89fa4ad2009-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 Huber608d77b2010-06-23 16:40:57 -0700710 return STAGEFRIGHT_PLAYER;
The Android Open Source Project89fa4ad2009-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 Huber47f59cf2009-08-07 09:30:32 -0700729 return getDefaultPlayerType();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800730}
731
James Dong148c1a22009-09-06 14:29:45 -0700732player_type getPlayerType(const char* url)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800733{
Nicolas Catania14d27472009-07-13 14:37:49 -0700734 if (TestPlayerStub::canBeUsed(url)) {
735 return TEST_PLAYER;
736 }
737
Andreas Hubered8d14f2011-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 Huber5bc087c2010-12-23 10:27:40 -0800743
Andreas Hubered8d14f2011-02-16 09:05:38 -0800744 if (strstr(url,"m3u8")) {
745 return NU_PLAYER;
Andreas Huber5bc087c2010-12-23 10:27:40 -0800746 }
747 }
748
The Android Open Source Project89fa4ad2009-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 Enofc1c7b92010-03-19 23:18:02 +0900755 if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) {
Andreas Huber608d77b2010-06-23 16:40:57 -0700756 return FILE_EXTS[i].playertype;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800757 }
758 }
759 }
760
Andreas Huber47f59cf2009-08-07 09:30:32 -0700761 return getDefaultPlayerType();
The Android Open Source Project89fa4ad2009-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 Project89fa4ad2009-03-03 19:31:44 -0800769 case SONIVOX_PLAYER:
770 LOGV(" create MidiFile");
771 p = new MidiFile();
772 break;
Andreas Huber20111aa2009-07-14 16:56:47 -0700773 case STAGEFRIGHT_PLAYER:
774 LOGV(" create StagefrightPlayer");
775 p = new StagefrightPlayer;
776 break;
Andreas Huberf9334412010-12-15 15:17:42 -0800777 case NU_PLAYER:
778 LOGV(" create NuPlayer");
779 p = new NuPlayerDriver;
780 break;
Nicolas Catania14d27472009-07-13 14:37:49 -0700781 case TEST_PLAYER:
782 LOGV("Create Test Player stub");
783 p = new TestPlayerStub();
784 break;
James Dong30d713a2010-11-10 18:42:40 -0800785 default:
786 LOGE("Unknown player type: %d", playerType);
787 return NULL;
The Android Open Source Project89fa4ad2009-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 Huber2db84552010-01-28 11:19:57 -0800816status_t MediaPlayerService::Client::setDataSource(
817 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-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 Laurenta514bdb2010-06-21 09:27:30 -0700846 mAudioOutput = new AudioOutput(mAudioSessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800847 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
848 }
849
850 // now set data source
851 LOGV(" setDataSource");
Andreas Huber2db84552010-01-28 11:19:57 -0800852 mStatus = p->setDataSource(url, headers);
Nicolas Catania14d27472009-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 Project89fa4ad2009-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 Laurenta514bdb2010-06-21 09:27:30 -0700896 mAudioOutput = new AudioOutput(mAudioSessionId);
The Android Open Source Project89fa4ad2009-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 Hubere2b10282010-11-23 11:41:34 -0800906status_t MediaPlayerService::Client::setDataSource(
907 const sp<IStreamSource> &source) {
908 // create the right type of player
Andreas Huberf9334412010-12-15 15:17:42 -0800909 sp<MediaPlayerBase> p = createPlayer(NU_PLAYER);
Andreas Hubere2b10282010-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 Huber5daeb122010-08-16 08:49:37 -0700930status_t MediaPlayerService::Client::setVideoSurface(const sp<Surface>& surface)
The Android Open Source Project89fa4ad2009-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
Glenn Kasten11731182011-02-08 17:26:17 -0800938status_t MediaPlayerService::Client::setVideoSurfaceTexture(
939 const sp<ISurfaceTexture>& surfaceTexture)
940{
941 LOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, surfaceTexture.get());
942 sp<MediaPlayerBase> p = getPlayer();
943 if (p == 0) return UNKNOWN_ERROR;
944 return p->setVideoSurfaceTexture(surfaceTexture);
945}
946
Nicolas Catania1d187f12009-05-12 23:25:55 -0700947status_t MediaPlayerService::Client::invoke(const Parcel& request,
948 Parcel *reply)
949{
950 sp<MediaPlayerBase> p = getPlayer();
951 if (p == NULL) return UNKNOWN_ERROR;
952 return p->invoke(request, reply);
953}
954
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700955// This call doesn't need to access the native player.
956status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
957{
958 status_t status;
nikoa64c8c72009-07-20 15:07:26 -0700959 media::Metadata::Filter allow, drop;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700960
Nicolas Catania48290382009-07-10 13:53:06 -0700961 if (unmarshallFilter(filter, &allow, &status) &&
962 unmarshallFilter(filter, &drop, &status)) {
963 Mutex::Autolock lock(mLock);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700964
965 mMetadataAllow = allow;
966 mMetadataDrop = drop;
967 }
968 return status;
969}
970
Nicolas Catania48290382009-07-10 13:53:06 -0700971status_t MediaPlayerService::Client::getMetadata(
972 bool update_only, bool apply_filter, Parcel *reply)
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700973{
nikoa64c8c72009-07-20 15:07:26 -0700974 sp<MediaPlayerBase> player = getPlayer();
975 if (player == 0) return UNKNOWN_ERROR;
Nicolas Catania48290382009-07-10 13:53:06 -0700976
nikod608a812009-07-16 16:39:53 -0700977 status_t status;
978 // Placeholder for the return code, updated by the caller.
979 reply->writeInt32(-1);
980
nikoa64c8c72009-07-20 15:07:26 -0700981 media::Metadata::Filter ids;
Nicolas Catania48290382009-07-10 13:53:06 -0700982
983 // We don't block notifications while we fetch the data. We clear
984 // mMetadataUpdated first so we don't lose notifications happening
985 // during the rest of this call.
986 {
987 Mutex::Autolock lock(mLock);
988 if (update_only) {
nikod608a812009-07-16 16:39:53 -0700989 ids = mMetadataUpdated;
Nicolas Catania48290382009-07-10 13:53:06 -0700990 }
991 mMetadataUpdated.clear();
992 }
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700993
nikoa64c8c72009-07-20 15:07:26 -0700994 media::Metadata metadata(reply);
Nicolas Catania48290382009-07-10 13:53:06 -0700995
nikoa64c8c72009-07-20 15:07:26 -0700996 metadata.appendHeader();
997 status = player->getMetadata(ids, reply);
nikod608a812009-07-16 16:39:53 -0700998
999 if (status != OK) {
nikoa64c8c72009-07-20 15:07:26 -07001000 metadata.resetParcel();
nikod608a812009-07-16 16:39:53 -07001001 LOGE("getMetadata failed %d", status);
1002 return status;
1003 }
1004
1005 // FIXME: Implement filtering on the result. Not critical since
1006 // filtering takes place on the update notifications already. This
1007 // would be when all the metadata are fetch and a filter is set.
1008
nikod608a812009-07-16 16:39:53 -07001009 // Everything is fine, update the metadata length.
nikoa64c8c72009-07-20 15:07:26 -07001010 metadata.updateLength();
nikod608a812009-07-16 16:39:53 -07001011 return OK;
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -07001012}
1013
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001014status_t MediaPlayerService::Client::prepareAsync()
1015{
1016 LOGV("[%d] prepareAsync", mConnId);
1017 sp<MediaPlayerBase> p = getPlayer();
1018 if (p == 0) return UNKNOWN_ERROR;
1019 status_t ret = p->prepareAsync();
1020#if CALLBACK_ANTAGONIZER
1021 LOGD("start Antagonizer");
1022 if (ret == NO_ERROR) mAntagonizer->start();
1023#endif
1024 return ret;
1025}
1026
1027status_t MediaPlayerService::Client::start()
1028{
1029 LOGV("[%d] start", mConnId);
1030 sp<MediaPlayerBase> p = getPlayer();
1031 if (p == 0) return UNKNOWN_ERROR;
1032 p->setLooping(mLoop);
1033 return p->start();
1034}
1035
1036status_t MediaPlayerService::Client::stop()
1037{
1038 LOGV("[%d] stop", mConnId);
1039 sp<MediaPlayerBase> p = getPlayer();
1040 if (p == 0) return UNKNOWN_ERROR;
1041 return p->stop();
1042}
1043
1044status_t MediaPlayerService::Client::pause()
1045{
1046 LOGV("[%d] pause", mConnId);
1047 sp<MediaPlayerBase> p = getPlayer();
1048 if (p == 0) return UNKNOWN_ERROR;
1049 return p->pause();
1050}
1051
1052status_t MediaPlayerService::Client::isPlaying(bool* state)
1053{
1054 *state = false;
1055 sp<MediaPlayerBase> p = getPlayer();
1056 if (p == 0) return UNKNOWN_ERROR;
1057 *state = p->isPlaying();
1058 LOGV("[%d] isPlaying: %d", mConnId, *state);
1059 return NO_ERROR;
1060}
1061
1062status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
1063{
1064 LOGV("getCurrentPosition");
1065 sp<MediaPlayerBase> p = getPlayer();
1066 if (p == 0) return UNKNOWN_ERROR;
1067 status_t ret = p->getCurrentPosition(msec);
1068 if (ret == NO_ERROR) {
1069 LOGV("[%d] getCurrentPosition = %d", mConnId, *msec);
1070 } else {
1071 LOGE("getCurrentPosition returned %d", ret);
1072 }
1073 return ret;
1074}
1075
1076status_t MediaPlayerService::Client::getDuration(int *msec)
1077{
1078 LOGV("getDuration");
1079 sp<MediaPlayerBase> p = getPlayer();
1080 if (p == 0) return UNKNOWN_ERROR;
1081 status_t ret = p->getDuration(msec);
1082 if (ret == NO_ERROR) {
1083 LOGV("[%d] getDuration = %d", mConnId, *msec);
1084 } else {
1085 LOGE("getDuration returned %d", ret);
1086 }
1087 return ret;
1088}
1089
1090status_t MediaPlayerService::Client::seekTo(int msec)
1091{
1092 LOGV("[%d] seekTo(%d)", mConnId, msec);
1093 sp<MediaPlayerBase> p = getPlayer();
1094 if (p == 0) return UNKNOWN_ERROR;
1095 return p->seekTo(msec);
1096}
1097
1098status_t MediaPlayerService::Client::reset()
1099{
1100 LOGV("[%d] reset", mConnId);
1101 sp<MediaPlayerBase> p = getPlayer();
1102 if (p == 0) return UNKNOWN_ERROR;
1103 return p->reset();
1104}
1105
1106status_t MediaPlayerService::Client::setAudioStreamType(int type)
1107{
1108 LOGV("[%d] setAudioStreamType(%d)", mConnId, type);
1109 // TODO: for hardware output, call player instead
1110 Mutex::Autolock l(mLock);
1111 if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
1112 return NO_ERROR;
1113}
1114
1115status_t MediaPlayerService::Client::setLooping(int loop)
1116{
1117 LOGV("[%d] setLooping(%d)", mConnId, loop);
1118 mLoop = loop;
1119 sp<MediaPlayerBase> p = getPlayer();
1120 if (p != 0) return p->setLooping(loop);
1121 return NO_ERROR;
1122}
1123
1124status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
1125{
1126 LOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
1127 // TODO: for hardware output, call player instead
1128 Mutex::Autolock l(mLock);
1129 if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
1130 return NO_ERROR;
1131}
1132
Eric Laurent2beeb502010-07-16 07:43:46 -07001133status_t MediaPlayerService::Client::setAuxEffectSendLevel(float level)
1134{
1135 LOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
1136 Mutex::Autolock l(mLock);
1137 if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
1138 return NO_ERROR;
1139}
1140
1141status_t MediaPlayerService::Client::attachAuxEffect(int effectId)
1142{
1143 LOGV("[%d] attachAuxEffect(%d)", mConnId, effectId);
1144 Mutex::Autolock l(mLock);
1145 if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId);
1146 return NO_ERROR;
1147}
Nicolas Catania48290382009-07-10 13:53:06 -07001148
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001149void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
1150{
1151 Client* client = static_cast<Client*>(cookie);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001152
1153 if (MEDIA_INFO == msg &&
Nicolas Catania48290382009-07-10 13:53:06 -07001154 MEDIA_INFO_METADATA_UPDATE == ext1) {
nikoa64c8c72009-07-20 15:07:26 -07001155 const media::Metadata::Type metadata_type = ext2;
Nicolas Catania48290382009-07-10 13:53:06 -07001156
1157 if(client->shouldDropMetadata(metadata_type)) {
1158 return;
1159 }
1160
1161 // Update the list of metadata that have changed. getMetadata
1162 // also access mMetadataUpdated and clears it.
1163 client->addNewMetadataUpdate(metadata_type);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001164 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001165 LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
1166 client->mClient->notify(msg, ext1, ext2);
1167}
1168
Nicolas Catania48290382009-07-10 13:53:06 -07001169
nikoa64c8c72009-07-20 15:07:26 -07001170bool MediaPlayerService::Client::shouldDropMetadata(media::Metadata::Type code) const
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001171{
Nicolas Catania48290382009-07-10 13:53:06 -07001172 Mutex::Autolock lock(mLock);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001173
Nicolas Catania48290382009-07-10 13:53:06 -07001174 if (findMetadata(mMetadataDrop, code)) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001175 return true;
1176 }
1177
Nicolas Catania48290382009-07-10 13:53:06 -07001178 if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001179 return false;
Nicolas Catania48290382009-07-10 13:53:06 -07001180 } else {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001181 return true;
1182 }
1183}
1184
Nicolas Catania48290382009-07-10 13:53:06 -07001185
nikoa64c8c72009-07-20 15:07:26 -07001186void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
Nicolas Catania48290382009-07-10 13:53:06 -07001187 Mutex::Autolock lock(mLock);
1188 if (mMetadataUpdated.indexOf(metadata_type) < 0) {
1189 mMetadataUpdated.add(metadata_type);
1190 }
1191}
1192
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001193#if CALLBACK_ANTAGONIZER
1194const int Antagonizer::interval = 10000; // 10 msecs
1195
1196Antagonizer::Antagonizer(notify_callback_f cb, void* client) :
1197 mExit(false), mActive(false), mClient(client), mCb(cb)
1198{
1199 createThread(callbackThread, this);
1200}
1201
1202void Antagonizer::kill()
1203{
1204 Mutex::Autolock _l(mLock);
1205 mActive = false;
1206 mExit = true;
1207 mCondition.wait(mLock);
1208}
1209
1210int Antagonizer::callbackThread(void* user)
1211{
1212 LOGD("Antagonizer started");
1213 Antagonizer* p = reinterpret_cast<Antagonizer*>(user);
1214 while (!p->mExit) {
1215 if (p->mActive) {
1216 LOGV("send event");
1217 p->mCb(p->mClient, 0, 0, 0);
1218 }
1219 usleep(interval);
1220 }
1221 Mutex::Autolock _l(p->mLock);
1222 p->mCondition.signal();
1223 LOGD("Antagonizer stopped");
1224 return 0;
1225}
1226#endif
1227
1228static size_t kDefaultHeapSize = 1024 * 1024; // 1MB
1229
1230sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
1231{
1232 LOGV("decode(%s)", url);
1233 sp<MemoryBase> mem;
1234 sp<MediaPlayerBase> player;
1235
1236 // Protect our precious, precious DRMd ringtones by only allowing
1237 // decoding of http, but not filesystem paths or content Uris.
1238 // If the application wants to decode those, it should open a
1239 // filedescriptor for them and use that.
1240 if (url != NULL && strncmp(url, "http://", 7) != 0) {
1241 LOGD("Can't decode %s by path, use filedescriptor instead", url);
1242 return mem;
1243 }
1244
1245 player_type playerType = getPlayerType(url);
1246 LOGV("player type = %d", playerType);
1247
1248 // create the right type of player
1249 sp<AudioCache> cache = new AudioCache(url);
1250 player = android::createPlayer(playerType, cache.get(), cache->notify);
1251 if (player == NULL) goto Exit;
1252 if (player->hardwareOutput()) goto Exit;
1253
1254 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1255
1256 // set data source
1257 if (player->setDataSource(url) != NO_ERROR) goto Exit;
1258
1259 LOGV("prepare");
1260 player->prepareAsync();
1261
1262 LOGV("wait for prepare");
1263 if (cache->wait() != NO_ERROR) goto Exit;
1264
1265 LOGV("start");
1266 player->start();
1267
1268 LOGV("wait for playback complete");
1269 if (cache->wait() != NO_ERROR) goto Exit;
1270
1271 mem = new MemoryBase(cache->getHeap(), 0, cache->size());
1272 *pSampleRate = cache->sampleRate();
1273 *pNumChannels = cache->channelCount();
1274 *pFormat = cache->format();
1275 LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
1276
1277Exit:
1278 if (player != 0) player->reset();
1279 return mem;
1280}
1281
1282sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
1283{
1284 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
1285 sp<MemoryBase> mem;
1286 sp<MediaPlayerBase> player;
1287
1288 player_type playerType = getPlayerType(fd, offset, length);
1289 LOGV("player type = %d", playerType);
1290
1291 // create the right type of player
1292 sp<AudioCache> cache = new AudioCache("decode_fd");
1293 player = android::createPlayer(playerType, cache.get(), cache->notify);
1294 if (player == NULL) goto Exit;
1295 if (player->hardwareOutput()) goto Exit;
1296
1297 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1298
1299 // set data source
1300 if (player->setDataSource(fd, offset, length) != NO_ERROR) goto Exit;
1301
1302 LOGV("prepare");
1303 player->prepareAsync();
1304
1305 LOGV("wait for prepare");
1306 if (cache->wait() != NO_ERROR) goto Exit;
1307
1308 LOGV("start");
1309 player->start();
1310
1311 LOGV("wait for playback complete");
1312 if (cache->wait() != NO_ERROR) goto Exit;
1313
1314 mem = new MemoryBase(cache->getHeap(), 0, cache->size());
1315 *pSampleRate = cache->sampleRate();
1316 *pNumChannels = cache->channelCount();
1317 *pFormat = cache->format();
1318 LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
1319
1320Exit:
1321 if (player != 0) player->reset();
1322 ::close(fd);
1323 return mem;
1324}
1325
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001326
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001327#undef LOG_TAG
1328#define LOG_TAG "AudioSink"
Eric Laurenta514bdb2010-06-21 09:27:30 -07001329MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
Andreas Huber20111aa2009-07-14 16:56:47 -07001330 : mCallback(NULL),
Eric Laurenta514bdb2010-06-21 09:27:30 -07001331 mCallbackCookie(NULL),
1332 mSessionId(sessionId) {
1333 LOGV("AudioOutput(%d)", sessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001334 mTrack = 0;
1335 mStreamType = AudioSystem::MUSIC;
1336 mLeftVolume = 1.0;
1337 mRightVolume = 1.0;
1338 mLatency = 0;
1339 mMsecsPerFrame = 0;
Eric Laurent2beeb502010-07-16 07:43:46 -07001340 mAuxEffectId = 0;
1341 mSendLevel = 0.0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001342 setMinBufferCount();
1343}
1344
1345MediaPlayerService::AudioOutput::~AudioOutput()
1346{
1347 close();
1348}
1349
1350void MediaPlayerService::AudioOutput::setMinBufferCount()
1351{
1352 char value[PROPERTY_VALUE_MAX];
1353 if (property_get("ro.kernel.qemu", value, 0)) {
1354 mIsOnEmulator = true;
1355 mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
1356 }
1357}
1358
1359bool MediaPlayerService::AudioOutput::isOnEmulator()
1360{
1361 setMinBufferCount();
1362 return mIsOnEmulator;
1363}
1364
1365int MediaPlayerService::AudioOutput::getMinBufferCount()
1366{
1367 setMinBufferCount();
1368 return mMinBufferCount;
1369}
1370
1371ssize_t MediaPlayerService::AudioOutput::bufferSize() const
1372{
1373 if (mTrack == 0) return NO_INIT;
1374 return mTrack->frameCount() * frameSize();
1375}
1376
1377ssize_t MediaPlayerService::AudioOutput::frameCount() const
1378{
1379 if (mTrack == 0) return NO_INIT;
1380 return mTrack->frameCount();
1381}
1382
1383ssize_t MediaPlayerService::AudioOutput::channelCount() const
1384{
1385 if (mTrack == 0) return NO_INIT;
1386 return mTrack->channelCount();
1387}
1388
1389ssize_t MediaPlayerService::AudioOutput::frameSize() const
1390{
1391 if (mTrack == 0) return NO_INIT;
1392 return mTrack->frameSize();
1393}
1394
1395uint32_t MediaPlayerService::AudioOutput::latency () const
1396{
1397 return mLatency;
1398}
1399
1400float MediaPlayerService::AudioOutput::msecsPerFrame() const
1401{
1402 return mMsecsPerFrame;
1403}
1404
Eric Laurent342e9cf2010-01-19 17:37:09 -08001405status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position)
1406{
1407 if (mTrack == 0) return NO_INIT;
1408 return mTrack->getPosition(position);
1409}
1410
Andreas Huber20111aa2009-07-14 16:56:47 -07001411status_t MediaPlayerService::AudioOutput::open(
1412 uint32_t sampleRate, int channelCount, int format, int bufferCount,
1413 AudioCallback cb, void *cookie)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001414{
Andreas Huber20111aa2009-07-14 16:56:47 -07001415 mCallback = cb;
1416 mCallbackCookie = cookie;
1417
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001418 // Check argument "bufferCount" against the mininum buffer count
1419 if (bufferCount < mMinBufferCount) {
1420 LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
1421 bufferCount = mMinBufferCount;
1422
1423 }
Eric Laurenta514bdb2010-06-21 09:27:30 -07001424 LOGV("open(%u, %d, %d, %d, %d)", sampleRate, channelCount, format, bufferCount,mSessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001425 if (mTrack) close();
1426 int afSampleRate;
1427 int afFrameCount;
1428 int frameCount;
1429
1430 if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
1431 return NO_INIT;
1432 }
1433 if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
1434 return NO_INIT;
1435 }
1436
1437 frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
Andreas Huber20111aa2009-07-14 16:56:47 -07001438
1439 AudioTrack *t;
1440 if (mCallback != NULL) {
1441 t = new AudioTrack(
Eric Laurentc2f1f072009-07-17 12:17:14 -07001442 mStreamType,
1443 sampleRate,
1444 format,
1445 (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
1446 frameCount,
1447 0 /* flags */,
1448 CallbackWrapper,
Eric Laurenta514bdb2010-06-21 09:27:30 -07001449 this,
1450 0,
1451 mSessionId);
Andreas Huber20111aa2009-07-14 16:56:47 -07001452 } else {
1453 t = new AudioTrack(
Eric Laurentc2f1f072009-07-17 12:17:14 -07001454 mStreamType,
1455 sampleRate,
1456 format,
1457 (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
Eric Laurenta514bdb2010-06-21 09:27:30 -07001458 frameCount,
1459 0,
1460 NULL,
1461 NULL,
1462 0,
1463 mSessionId);
Andreas Huber20111aa2009-07-14 16:56:47 -07001464 }
1465
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001466 if ((t == 0) || (t->initCheck() != NO_ERROR)) {
1467 LOGE("Unable to create audio track");
1468 delete t;
1469 return NO_INIT;
1470 }
1471
1472 LOGV("setVolume");
1473 t->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -07001474
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001475 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Dave Sparks1d711f62009-12-03 10:13:32 -08001476 mLatency = t->latency();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001477 mTrack = t;
Eric Laurent2beeb502010-07-16 07:43:46 -07001478
1479 t->setAuxEffectSendLevel(mSendLevel);
1480 return t->attachAuxEffect(mAuxEffectId);;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001481}
1482
1483void MediaPlayerService::AudioOutput::start()
1484{
1485 LOGV("start");
1486 if (mTrack) {
1487 mTrack->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -07001488 mTrack->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001489 mTrack->start();
1490 }
1491}
1492
Marco Nelissen7ee8ac92010-01-12 09:23:54 -08001493
1494
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001495ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
1496{
Andreas Huber20111aa2009-07-14 16:56:47 -07001497 LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
1498
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001499 //LOGV("write(%p, %u)", buffer, size);
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001500 if (mTrack) {
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001501 ssize_t ret = mTrack->write(buffer, size);
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001502 return ret;
1503 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001504 return NO_INIT;
1505}
1506
1507void MediaPlayerService::AudioOutput::stop()
1508{
1509 LOGV("stop");
1510 if (mTrack) mTrack->stop();
1511}
1512
1513void MediaPlayerService::AudioOutput::flush()
1514{
1515 LOGV("flush");
1516 if (mTrack) mTrack->flush();
1517}
1518
1519void MediaPlayerService::AudioOutput::pause()
1520{
1521 LOGV("pause");
1522 if (mTrack) mTrack->pause();
1523}
1524
1525void MediaPlayerService::AudioOutput::close()
1526{
1527 LOGV("close");
1528 delete mTrack;
1529 mTrack = 0;
1530}
1531
1532void MediaPlayerService::AudioOutput::setVolume(float left, float right)
1533{
1534 LOGV("setVolume(%f, %f)", left, right);
1535 mLeftVolume = left;
1536 mRightVolume = right;
1537 if (mTrack) {
1538 mTrack->setVolume(left, right);
1539 }
1540}
1541
Eric Laurent2beeb502010-07-16 07:43:46 -07001542status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
1543{
1544 LOGV("setAuxEffectSendLevel(%f)", level);
1545 mSendLevel = level;
1546 if (mTrack) {
1547 return mTrack->setAuxEffectSendLevel(level);
1548 }
1549 return NO_ERROR;
1550}
1551
1552status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
1553{
1554 LOGV("attachAuxEffect(%d)", effectId);
1555 mAuxEffectId = effectId;
1556 if (mTrack) {
1557 return mTrack->attachAuxEffect(effectId);
1558 }
1559 return NO_ERROR;
1560}
1561
Andreas Huber20111aa2009-07-14 16:56:47 -07001562// static
1563void MediaPlayerService::AudioOutput::CallbackWrapper(
1564 int event, void *cookie, void *info) {
Marco Nelissen7ee8ac92010-01-12 09:23:54 -08001565 //LOGV("callbackwrapper");
Andreas Huber20111aa2009-07-14 16:56:47 -07001566 if (event != AudioTrack::EVENT_MORE_DATA) {
1567 return;
1568 }
1569
1570 AudioOutput *me = (AudioOutput *)cookie;
1571 AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
1572
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001573 size_t actualSize = (*me->mCallback)(
Andreas Huber20111aa2009-07-14 16:56:47 -07001574 me, buffer->raw, buffer->size, me->mCallbackCookie);
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001575
Andreas Huber2e8ffaf2010-02-18 16:45:13 -08001576 buffer->size = actualSize;
1577
Andreas Huber20111aa2009-07-14 16:56:47 -07001578}
1579
Eric Laurent8c563ed2010-10-07 18:23:03 -07001580int MediaPlayerService::AudioOutput::getSessionId()
1581{
1582 return mSessionId;
1583}
1584
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001585#undef LOG_TAG
1586#define LOG_TAG "AudioCache"
1587MediaPlayerService::AudioCache::AudioCache(const char* name) :
1588 mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
1589 mError(NO_ERROR), mCommandComplete(false)
1590{
1591 // create ashmem heap
1592 mHeap = new MemoryHeapBase(kDefaultHeapSize, 0, name);
1593}
1594
1595uint32_t MediaPlayerService::AudioCache::latency () const
1596{
1597 return 0;
1598}
1599
1600float MediaPlayerService::AudioCache::msecsPerFrame() const
1601{
1602 return mMsecsPerFrame;
1603}
1604
Eric Laurent342e9cf2010-01-19 17:37:09 -08001605status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position)
1606{
1607 if (position == 0) return BAD_VALUE;
1608 *position = mSize;
1609 return NO_ERROR;
1610}
1611
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001612////////////////////////////////////////////////////////////////////////////////
1613
1614struct CallbackThread : public Thread {
1615 CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink,
1616 MediaPlayerBase::AudioSink::AudioCallback cb,
1617 void *cookie);
1618
1619protected:
1620 virtual ~CallbackThread();
1621
1622 virtual bool threadLoop();
1623
1624private:
1625 wp<MediaPlayerBase::AudioSink> mSink;
1626 MediaPlayerBase::AudioSink::AudioCallback mCallback;
1627 void *mCookie;
1628 void *mBuffer;
1629 size_t mBufferSize;
1630
1631 CallbackThread(const CallbackThread &);
1632 CallbackThread &operator=(const CallbackThread &);
1633};
1634
1635CallbackThread::CallbackThread(
1636 const wp<MediaPlayerBase::AudioSink> &sink,
1637 MediaPlayerBase::AudioSink::AudioCallback cb,
1638 void *cookie)
1639 : mSink(sink),
1640 mCallback(cb),
1641 mCookie(cookie),
1642 mBuffer(NULL),
1643 mBufferSize(0) {
1644}
1645
1646CallbackThread::~CallbackThread() {
1647 if (mBuffer) {
1648 free(mBuffer);
1649 mBuffer = NULL;
1650 }
1651}
1652
1653bool CallbackThread::threadLoop() {
1654 sp<MediaPlayerBase::AudioSink> sink = mSink.promote();
1655 if (sink == NULL) {
1656 return false;
1657 }
1658
1659 if (mBuffer == NULL) {
1660 mBufferSize = sink->bufferSize();
1661 mBuffer = malloc(mBufferSize);
1662 }
1663
1664 size_t actualSize =
1665 (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie);
1666
1667 if (actualSize > 0) {
1668 sink->write(mBuffer, actualSize);
1669 }
1670
1671 return true;
1672}
1673
1674////////////////////////////////////////////////////////////////////////////////
1675
Andreas Huber20111aa2009-07-14 16:56:47 -07001676status_t MediaPlayerService::AudioCache::open(
1677 uint32_t sampleRate, int channelCount, int format, int bufferCount,
1678 AudioCallback cb, void *cookie)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001679{
Dave Sparks8eb80112009-12-09 20:20:26 -08001680 LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
Dave Sparks8eb80112009-12-09 20:20:26 -08001681 if (mHeap->getHeapID() < 0) {
1682 return NO_INIT;
1683 }
Andreas Huber20111aa2009-07-14 16:56:47 -07001684
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001685 mSampleRate = sampleRate;
1686 mChannelCount = (uint16_t)channelCount;
1687 mFormat = (uint16_t)format;
1688 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001689
1690 if (cb != NULL) {
1691 mCallbackThread = new CallbackThread(this, cb, cookie);
1692 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001693 return NO_ERROR;
1694}
1695
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001696void MediaPlayerService::AudioCache::start() {
1697 if (mCallbackThread != NULL) {
1698 mCallbackThread->run("AudioCache callback");
1699 }
1700}
1701
1702void MediaPlayerService::AudioCache::stop() {
1703 if (mCallbackThread != NULL) {
1704 mCallbackThread->requestExitAndWait();
1705 }
1706}
1707
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001708ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
1709{
1710 LOGV("write(%p, %u)", buffer, size);
1711 if ((buffer == 0) || (size == 0)) return size;
1712
1713 uint8_t* p = static_cast<uint8_t*>(mHeap->getBase());
1714 if (p == NULL) return NO_INIT;
1715 p += mSize;
1716 LOGV("memcpy(%p, %p, %u)", p, buffer, size);
1717 if (mSize + size > mHeap->getSize()) {
1718 LOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
1719 size = mHeap->getSize() - mSize;
1720 }
1721 memcpy(p, buffer, size);
1722 mSize += size;
1723 return size;
1724}
1725
1726// call with lock held
1727status_t MediaPlayerService::AudioCache::wait()
1728{
1729 Mutex::Autolock lock(mLock);
Dave Sparks4bbc0ba2010-03-01 19:29:58 -08001730 while (!mCommandComplete) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001731 mSignal.wait(mLock);
1732 }
1733 mCommandComplete = false;
1734
1735 if (mError == NO_ERROR) {
1736 LOGV("wait - success");
1737 } else {
1738 LOGV("wait - error");
1739 }
1740 return mError;
1741}
1742
1743void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int ext2)
1744{
1745 LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
1746 AudioCache* p = static_cast<AudioCache*>(cookie);
1747
1748 // ignore buffering messages
Dave Sparks8eb80112009-12-09 20:20:26 -08001749 switch (msg)
1750 {
1751 case MEDIA_ERROR:
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001752 LOGE("Error %d, %d occurred", ext1, ext2);
1753 p->mError = ext1;
Dave Sparks8eb80112009-12-09 20:20:26 -08001754 break;
1755 case MEDIA_PREPARED:
1756 LOGV("prepared");
1757 break;
1758 case MEDIA_PLAYBACK_COMPLETE:
1759 LOGV("playback complete");
1760 break;
1761 default:
1762 LOGV("ignored");
1763 return;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001764 }
1765
1766 // wake up thread
Dave Sparksfe4c6f02010-03-02 12:56:37 -08001767 Mutex::Autolock lock(p->mLock);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001768 p->mCommandComplete = true;
1769 p->mSignal.signal();
1770}
1771
Eric Laurent8c563ed2010-10-07 18:23:03 -07001772int MediaPlayerService::AudioCache::getSessionId()
1773{
1774 return 0;
1775}
1776
Gloria Wang7cf180c2011-02-19 18:37:57 -08001777void MediaPlayerService::addBatteryData(uint32_t params)
1778{
1779 Mutex::Autolock lock(mLock);
1780 int uid = IPCThreadState::self()->getCallingUid();
1781 if (uid == AID_MEDIA) {
1782 return;
1783 }
1784 int index = mBatteryData.indexOfKey(uid);
1785 int32_t time = systemTime() / 1000000L;
1786
1787 if (index < 0) { // create a new entry for this UID
1788 BatteryUsageInfo info;
1789 info.audioTotalTime = 0;
1790 info.videoTotalTime = 0;
1791 info.audioLastTime = 0;
1792 info.videoLastTime = 0;
1793 info.refCount = 0;
1794
1795 mBatteryData.add(uid, info);
1796 }
1797
1798 BatteryUsageInfo &info = mBatteryData.editValueFor(uid);
1799
1800 if (params & kBatteryDataCodecStarted) {
1801 if (params & kBatteryDataTrackAudio) {
1802 info.audioLastTime -= time;
1803 info.refCount ++;
1804 }
1805 if (params & kBatteryDataTrackVideo) {
1806 info.videoLastTime -= time;
1807 info.refCount ++;
1808 }
1809 } else {
1810 if (info.refCount == 0) {
1811 LOGW("Battery track warning: refCount is already 0");
1812 return;
1813 } else if (info.refCount < 0) {
1814 LOGE("Battery track error: refCount < 0");
1815 mBatteryData.removeItem(uid);
1816 return;
1817 }
1818
1819 if (params & kBatteryDataTrackAudio) {
1820 info.audioLastTime += time;
1821 info.refCount --;
1822 }
1823 if (params & kBatteryDataTrackVideo) {
1824 info.videoLastTime += time;
1825 info.refCount --;
1826 }
1827
1828 // no stream is being played by this UID
1829 if (info.refCount == 0) {
1830 info.audioTotalTime += info.audioLastTime;
1831 info.audioLastTime = 0;
1832 info.videoTotalTime += info.videoLastTime;
1833 info.videoLastTime = 0;
1834 }
1835 }
1836}
1837
1838status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
1839 Mutex::Autolock lock(mLock);
1840 BatteryUsageInfo info;
1841 int size = mBatteryData.size();
1842
1843 reply->writeInt32(size);
1844 int i = 0;
1845
1846 while (i < size) {
1847 info = mBatteryData.valueAt(i);
1848
1849 reply->writeInt32(mBatteryData.keyAt(i)); //UID
1850 reply->writeInt32(info.audioTotalTime);
1851 reply->writeInt32(info.videoTotalTime);
1852
1853 info.audioTotalTime = 0;
1854 info.videoTotalTime = 0;
1855
1856 // remove the UID entry where no stream is being played
1857 if (info.refCount <= 0) {
1858 mBatteryData.removeItemsAt(i);
1859 size --;
1860 i --;
1861 }
1862 i++;
1863 }
1864 return NO_ERROR;
1865}
nikoa64c8c72009-07-20 15:07:26 -07001866} // namespace android