blob: a43461408373b66d09dc9858e2cdcf2a92ea2613 [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>
James Dong8635b7b2011-03-14 17:01:38 -070054#include <media/MemoryLeakTrackUtil.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080055
Dima Zavin64760242011-05-11 14:15:23 -070056#include <system/audio.h>
Dima Zavinfce7a472011-04-19 22:30:36 -070057
Gloria Wang7cf180c2011-02-19 18:37:57 -080058#include <private/android_filesystem_config.h>
59
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080060#include "MediaRecorderClient.h"
61#include "MediaPlayerService.h"
62#include "MetadataRetrieverClient.h"
63
64#include "MidiFile.h"
Nicolas Catania14d27472009-07-13 14:37:49 -070065#include "TestPlayerStub.h"
Andreas Huber20111aa2009-07-14 16:56:47 -070066#include "StagefrightPlayer.h"
Andreas Huberf9334412010-12-15 15:17:42 -080067#include "nuplayer/NuPlayerDriver.h"
Andreas Huber20111aa2009-07-14 16:56:47 -070068
Andreas Huber20111aa2009-07-14 16:56:47 -070069#include <OMX.h>
Nicolas Catania14d27472009-07-13 14:37:49 -070070
Mike J. Chen9b153be2011-08-15 13:24:13 -070071namespace android {
72sp<MediaPlayerBase> createAAH_TXPlayer();
73sp<MediaPlayerBase> createAAH_RXPlayer();
74}
75
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070076namespace {
nikoa64c8c72009-07-20 15:07:26 -070077using android::media::Metadata;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070078using android::status_t;
79using android::OK;
80using android::BAD_VALUE;
81using android::NOT_ENOUGH_DATA;
82using android::Parcel;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070083
84// Max number of entries in the filter.
85const int kMaxFilterSize = 64; // I pulled that out of thin air.
86
nikoa64c8c72009-07-20 15:07:26 -070087// FIXME: Move all the metadata related function in the Metadata.cpp
nikod608a812009-07-16 16:39:53 -070088
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070089
90// Unmarshall a filter from a Parcel.
91// Filter format in a parcel:
92//
93// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
94// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95// | number of entries (n) |
96// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97// | metadata type 1 |
98// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99// | metadata type 2 |
100// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101// ....
102// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103// | metadata type n |
104// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105//
106// @param p Parcel that should start with a filter.
107// @param[out] filter On exit contains the list of metadata type to be
108// filtered.
109// @param[out] status On exit contains the status code to be returned.
110// @return true if the parcel starts with a valid filter.
111bool unmarshallFilter(const Parcel& p,
nikoa64c8c72009-07-20 15:07:26 -0700112 Metadata::Filter *filter,
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700113 status_t *status)
114{
Nicolas Catania48290382009-07-10 13:53:06 -0700115 int32_t val;
116 if (p.readInt32(&val) != OK)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700117 {
118 LOGE("Failed to read filter's length");
119 *status = NOT_ENOUGH_DATA;
120 return false;
121 }
122
Nicolas Catania48290382009-07-10 13:53:06 -0700123 if( val > kMaxFilterSize || val < 0)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700124 {
Nicolas Catania48290382009-07-10 13:53:06 -0700125 LOGE("Invalid filter len %d", val);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700126 *status = BAD_VALUE;
127 return false;
128 }
129
Nicolas Catania48290382009-07-10 13:53:06 -0700130 const size_t num = val;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700131
132 filter->clear();
Nicolas Catania48290382009-07-10 13:53:06 -0700133 filter->setCapacity(num);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700134
nikoa64c8c72009-07-20 15:07:26 -0700135 size_t size = num * sizeof(Metadata::Type);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700136
Nicolas Catania48290382009-07-10 13:53:06 -0700137
138 if (p.dataAvail() < size)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700139 {
Nicolas Catania48290382009-07-10 13:53:06 -0700140 LOGE("Filter too short expected %d but got %d", size, p.dataAvail());
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700141 *status = NOT_ENOUGH_DATA;
142 return false;
143 }
144
nikoa64c8c72009-07-20 15:07:26 -0700145 const Metadata::Type *data =
146 static_cast<const Metadata::Type*>(p.readInplace(size));
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700147
Nicolas Catania48290382009-07-10 13:53:06 -0700148 if (NULL == data)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700149 {
150 LOGE("Filter had no data");
151 *status = BAD_VALUE;
152 return false;
153 }
154
155 // TODO: The stl impl of vector would be more efficient here
156 // because it degenerates into a memcpy on pod types. Try to
157 // replace later or use stl::set.
Nicolas Catania48290382009-07-10 13:53:06 -0700158 for (size_t i = 0; i < num; ++i)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700159 {
Nicolas Catania48290382009-07-10 13:53:06 -0700160 filter->add(*data);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700161 ++data;
162 }
163 *status = OK;
164 return true;
165}
166
Nicolas Catania48290382009-07-10 13:53:06 -0700167// @param filter Of metadata type.
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700168// @param val To be searched.
169// @return true if a match was found.
nikoa64c8c72009-07-20 15:07:26 -0700170bool findMetadata(const Metadata::Filter& filter, const int32_t val)
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700171{
172 // Deal with empty and ANY right away
173 if (filter.isEmpty()) return false;
nikoa64c8c72009-07-20 15:07:26 -0700174 if (filter[0] == Metadata::kAny) return true;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700175
Nicolas Catania48290382009-07-10 13:53:06 -0700176 return filter.indexOf(val) >= 0;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700177}
178
179} // anonymous namespace
180
181
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800182namespace android {
183
Dave Burked681bbb2011-08-30 14:39:17 +0100184static bool checkPermission(const char* permissionString) {
185#ifndef HAVE_ANDROID_OS
186 return true;
187#endif
188 if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
189 bool ok = checkCallingPermission(String16(permissionString));
190 if (!ok) LOGE("Request requires %s", permissionString);
191 return ok;
192}
193
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800194// TODO: Temp hack until we can register players
195typedef struct {
196 const char *extension;
197 const player_type playertype;
198} extmap;
199extmap FILE_EXTS [] = {
200 {".mid", SONIVOX_PLAYER},
201 {".midi", SONIVOX_PLAYER},
202 {".smf", SONIVOX_PLAYER},
203 {".xmf", SONIVOX_PLAYER},
204 {".imy", SONIVOX_PLAYER},
205 {".rtttl", SONIVOX_PLAYER},
206 {".rtx", SONIVOX_PLAYER},
207 {".ota", SONIVOX_PLAYER},
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800208};
209
210// 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 -0800211/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
212/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
213
214void MediaPlayerService::instantiate() {
215 defaultServiceManager()->addService(
216 String16("media.player"), new MediaPlayerService());
217}
218
219MediaPlayerService::MediaPlayerService()
220{
221 LOGV("MediaPlayerService created");
222 mNextConnId = 1;
Gloria Wang9ee159b2011-02-24 14:51:45 -0800223
224 mBatteryAudio.refCount = 0;
225 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
226 mBatteryAudio.deviceOn[i] = 0;
227 mBatteryAudio.lastTime[i] = 0;
228 mBatteryAudio.totalTime[i] = 0;
229 }
230 // speaker is on by default
231 mBatteryAudio.deviceOn[SPEAKER] = 1;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800232}
233
234MediaPlayerService::~MediaPlayerService()
235{
236 LOGV("MediaPlayerService destroyed");
237}
238
239sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
240{
Gloria Wangdac6a312009-10-29 15:46:37 -0700241 sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid);
242 wp<MediaRecorderClient> w = recorder;
243 Mutex::Autolock lock(mLock);
244 mMediaRecorderClients.add(w);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800245 LOGV("Create new media recorder client from pid %d", pid);
246 return recorder;
247}
248
Gloria Wangdac6a312009-10-29 15:46:37 -0700249void MediaPlayerService::removeMediaRecorderClient(wp<MediaRecorderClient> client)
250{
251 Mutex::Autolock lock(mLock);
252 mMediaRecorderClients.remove(client);
253 LOGV("Delete media recorder client");
254}
255
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800256sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pid)
257{
258 sp<MetadataRetrieverClient> retriever = new MetadataRetrieverClient(pid);
259 LOGV("Create new media retriever from pid %d", pid);
260 return retriever;
261}
262
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800263sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,
Dave Burked681bbb2011-08-30 14:39:17 +0100264 int audioSessionId)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800265{
266 int32_t connId = android_atomic_inc(&mNextConnId);
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700267
268 sp<Client> c = new Client(
269 this, pid, connId, client, audioSessionId,
270 IPCThreadState::self()->getCallingUid());
271
Dave Burked681bbb2011-08-30 14:39:17 +0100272 LOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
273 IPCThreadState::self()->getCallingUid());
274
275 wp<Client> w = c;
276 {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800277 Mutex::Autolock lock(mLock);
278 mClients.add(w);
279 }
Andreas Hubere2b10282010-11-23 11:41:34 -0800280 return c;
281}
282
Andreas Huber318ad9c2009-10-15 13:46:54 -0700283sp<IOMX> MediaPlayerService::getOMX() {
284 Mutex::Autolock autoLock(mLock);
285
286 if (mOMX.get() == NULL) {
287 mOMX = new OMX;
288 }
289
290 return mOMX;
Andreas Huber20111aa2009-07-14 16:56:47 -0700291}
292
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800293status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
294{
295 const size_t SIZE = 256;
296 char buffer[SIZE];
297 String8 result;
298
299 result.append(" AudioCache\n");
300 if (mHeap != 0) {
301 snprintf(buffer, 255, " heap base(%p), size(%d), flags(%d), device(%s)\n",
302 mHeap->getBase(), mHeap->getSize(), mHeap->getFlags(), mHeap->getDevice());
303 result.append(buffer);
304 }
305 snprintf(buffer, 255, " msec per frame(%f), channel count(%d), format(%d), frame count(%ld)\n",
306 mMsecsPerFrame, mChannelCount, mFormat, mFrameCount);
307 result.append(buffer);
308 snprintf(buffer, 255, " sample rate(%d), size(%d), error(%d), command complete(%s)\n",
309 mSampleRate, mSize, mError, mCommandComplete?"true":"false");
310 result.append(buffer);
311 ::write(fd, result.string(), result.size());
312 return NO_ERROR;
313}
314
315status_t MediaPlayerService::AudioOutput::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(" AudioOutput\n");
322 snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
323 mStreamType, mLeftVolume, mRightVolume);
324 result.append(buffer);
325 snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
326 mMsecsPerFrame, mLatency);
327 result.append(buffer);
Eric Laurent2beeb502010-07-16 07:43:46 -0700328 snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
329 mAuxEffectId, mSendLevel);
330 result.append(buffer);
331
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800332 ::write(fd, result.string(), result.size());
333 if (mTrack != 0) {
334 mTrack->dump(fd, args);
335 }
336 return NO_ERROR;
337}
338
339status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args) const
340{
341 const size_t SIZE = 256;
342 char buffer[SIZE];
343 String8 result;
344 result.append(" Client\n");
345 snprintf(buffer, 255, " pid(%d), connId(%d), status(%d), looping(%s)\n",
346 mPid, mConnId, mStatus, mLoop?"true": "false");
347 result.append(buffer);
348 write(fd, result.string(), result.size());
Andreas Hubera0b1d4b2011-06-07 15:52:25 -0700349 if (mPlayer != NULL) {
350 mPlayer->dump(fd, args);
351 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800352 if (mAudioOutput != 0) {
353 mAudioOutput->dump(fd, args);
354 }
355 write(fd, "\n", 1);
356 return NO_ERROR;
357}
358
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800359status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
360{
361 const size_t SIZE = 256;
362 char buffer[SIZE];
363 String8 result;
364 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
365 snprintf(buffer, SIZE, "Permission Denial: "
366 "can't dump MediaPlayerService from pid=%d, uid=%d\n",
367 IPCThreadState::self()->getCallingPid(),
368 IPCThreadState::self()->getCallingUid());
369 result.append(buffer);
370 } else {
371 Mutex::Autolock lock(mLock);
372 for (int i = 0, n = mClients.size(); i < n; ++i) {
373 sp<Client> c = mClients[i].promote();
374 if (c != 0) c->dump(fd, args);
375 }
James Dongb9141222010-07-08 11:16:11 -0700376 if (mMediaRecorderClients.size() == 0) {
377 result.append(" No media recorder client\n\n");
378 } else {
379 for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
380 sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
381 snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
382 result.append(buffer);
383 write(fd, result.string(), result.size());
384 result = "\n";
385 c->dump(fd, args);
386 }
Gloria Wangdac6a312009-10-29 15:46:37 -0700387 }
388
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800389 result.append(" Files opened and/or mapped:\n");
Glenn Kasten0512ab52011-05-04 17:58:57 -0700390 snprintf(buffer, SIZE, "/proc/%d/maps", gettid());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800391 FILE *f = fopen(buffer, "r");
392 if (f) {
393 while (!feof(f)) {
394 fgets(buffer, SIZE, f);
Dave Sparks02fa8342010-09-27 16:55:18 -0700395 if (strstr(buffer, " /mnt/sdcard/") ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800396 strstr(buffer, " /system/sounds/") ||
Dave Sparks02fa8342010-09-27 16:55:18 -0700397 strstr(buffer, " /data/") ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800398 strstr(buffer, " /system/media/")) {
399 result.append(" ");
400 result.append(buffer);
401 }
402 }
403 fclose(f);
404 } else {
405 result.append("couldn't open ");
406 result.append(buffer);
407 result.append("\n");
408 }
409
Glenn Kasten0512ab52011-05-04 17:58:57 -0700410 snprintf(buffer, SIZE, "/proc/%d/fd", gettid());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800411 DIR *d = opendir(buffer);
412 if (d) {
413 struct dirent *ent;
414 while((ent = readdir(d)) != NULL) {
415 if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
Glenn Kasten0512ab52011-05-04 17:58:57 -0700416 snprintf(buffer, SIZE, "/proc/%d/fd/%s", gettid(), ent->d_name);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800417 struct stat s;
418 if (lstat(buffer, &s) == 0) {
419 if ((s.st_mode & S_IFMT) == S_IFLNK) {
420 char linkto[256];
421 int len = readlink(buffer, linkto, sizeof(linkto));
422 if(len > 0) {
423 if(len > 255) {
424 linkto[252] = '.';
425 linkto[253] = '.';
426 linkto[254] = '.';
427 linkto[255] = 0;
428 } else {
429 linkto[len] = 0;
430 }
Dave Sparks02fa8342010-09-27 16:55:18 -0700431 if (strstr(linkto, "/mnt/sdcard/") == linkto ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800432 strstr(linkto, "/system/sounds/") == linkto ||
Dave Sparks02fa8342010-09-27 16:55:18 -0700433 strstr(linkto, "/data/") == linkto ||
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800434 strstr(linkto, "/system/media/") == linkto) {
435 result.append(" ");
436 result.append(buffer);
437 result.append(" -> ");
438 result.append(linkto);
439 result.append("\n");
440 }
441 }
442 } else {
443 result.append(" unexpected type for ");
444 result.append(buffer);
445 result.append("\n");
446 }
447 }
448 }
449 }
450 closedir(d);
451 } else {
452 result.append("couldn't open ");
453 result.append(buffer);
454 result.append("\n");
455 }
456
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800457 bool dumpMem = false;
458 for (size_t i = 0; i < args.size(); i++) {
459 if (args[i] == String16("-m")) {
460 dumpMem = true;
461 }
462 }
463 if (dumpMem) {
James Dong8635b7b2011-03-14 17:01:38 -0700464 dumpMemoryAddresses(fd);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800465 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800466 }
467 write(fd, result.string(), result.size());
468 return NO_ERROR;
469}
470
471void MediaPlayerService::removeClient(wp<Client> client)
472{
473 Mutex::Autolock lock(mLock);
474 mClients.remove(client);
475}
476
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700477MediaPlayerService::Client::Client(
478 const sp<MediaPlayerService>& service, pid_t pid,
479 int32_t connId, const sp<IMediaPlayerClient>& client,
480 int audioSessionId, uid_t uid)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800481{
482 LOGV("Client(%d) constructor", connId);
483 mPid = pid;
484 mConnId = connId;
485 mService = service;
486 mClient = client;
487 mLoop = false;
488 mStatus = NO_INIT;
Eric Laurenta514bdb2010-06-21 09:27:30 -0700489 mAudioSessionId = audioSessionId;
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700490 mUID = uid;
Eric Laurenta514bdb2010-06-21 09:27:30 -0700491
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800492#if CALLBACK_ANTAGONIZER
493 LOGD("create Antagonizer");
494 mAntagonizer = new Antagonizer(notify, this);
495#endif
496}
497
498MediaPlayerService::Client::~Client()
499{
500 LOGV("Client(%d) destructor pid = %d", mConnId, mPid);
501 mAudioOutput.clear();
502 wp<Client> client(this);
503 disconnect();
504 mService->removeClient(client);
505}
506
507void MediaPlayerService::Client::disconnect()
508{
509 LOGV("disconnect(%d) from pid %d", mConnId, mPid);
510 // grab local reference and clear main reference to prevent future
511 // access to object
512 sp<MediaPlayerBase> p;
513 {
514 Mutex::Autolock l(mLock);
515 p = mPlayer;
516 }
Dave Sparks795fa582009-03-24 17:57:12 -0700517 mClient.clear();
Andreas Huber20111aa2009-07-14 16:56:47 -0700518
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800519 mPlayer.clear();
520
521 // clear the notification to prevent callbacks to dead client
522 // and reset the player. We assume the player will serialize
523 // access to itself if necessary.
524 if (p != 0) {
525 p->setNotifyCallback(0, 0);
526#if CALLBACK_ANTAGONIZER
527 LOGD("kill Antagonizer");
528 mAntagonizer->kill();
529#endif
530 p->reset();
531 }
532
533 IPCThreadState::self()->flushCommands();
534}
535
Andreas Huber47f59cf2009-08-07 09:30:32 -0700536static player_type getDefaultPlayerType() {
Andreas Huber608d77b2010-06-23 16:40:57 -0700537 return STAGEFRIGHT_PLAYER;
Andreas Huber47f59cf2009-08-07 09:30:32 -0700538}
539
James Dong148c1a22009-09-06 14:29:45 -0700540player_type getPlayerType(int fd, int64_t offset, int64_t length)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800541{
542 char buf[20];
543 lseek(fd, offset, SEEK_SET);
544 read(fd, buf, sizeof(buf));
545 lseek(fd, offset, SEEK_SET);
546
547 long ident = *((long*)buf);
548
549 // Ogg vorbis?
550 if (ident == 0x5367674f) // 'OggS'
Andreas Huber608d77b2010-06-23 16:40:57 -0700551 return STAGEFRIGHT_PLAYER;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800552
553 // Some kind of MIDI?
554 EAS_DATA_HANDLE easdata;
555 if (EAS_Init(&easdata) == EAS_SUCCESS) {
556 EAS_FILE locator;
557 locator.path = NULL;
558 locator.fd = fd;
559 locator.offset = offset;
560 locator.length = length;
561 EAS_HANDLE eashandle;
562 if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
563 EAS_CloseFile(easdata, eashandle);
564 EAS_Shutdown(easdata);
565 return SONIVOX_PLAYER;
566 }
567 EAS_Shutdown(easdata);
568 }
569
Andreas Huber47f59cf2009-08-07 09:30:32 -0700570 return getDefaultPlayerType();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800571}
572
James Dong148c1a22009-09-06 14:29:45 -0700573player_type getPlayerType(const char* url)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800574{
Nicolas Catania14d27472009-07-13 14:37:49 -0700575 if (TestPlayerStub::canBeUsed(url)) {
576 return TEST_PLAYER;
577 }
578
Andreas Huber0a73d812011-03-21 16:28:04 -0700579 if (!strncasecmp("http://", url, 7)
580 || !strncasecmp("https://", url, 8)) {
Andreas Hubered8d14f2011-02-16 09:05:38 -0800581 size_t len = strlen(url);
582 if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
583 return NU_PLAYER;
584 }
Andreas Huber5bc087c2010-12-23 10:27:40 -0800585
Andreas Hubered8d14f2011-02-16 09:05:38 -0800586 if (strstr(url,"m3u8")) {
587 return NU_PLAYER;
Andreas Huber5bc087c2010-12-23 10:27:40 -0800588 }
589 }
590
Mike J. Chen9b153be2011-08-15 13:24:13 -0700591 if (!strncasecmp("aahRX://", url, 8)) {
592 return AAH_RX_PLAYER;
593 }
594
595 if (!strncasecmp("aahTX://", url, 8)) {
596 return AAH_TX_PLAYER;
597 }
598
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800599 // use MidiFile for MIDI extensions
600 int lenURL = strlen(url);
601 for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
602 int len = strlen(FILE_EXTS[i].extension);
603 int start = lenURL - len;
604 if (start > 0) {
Atsushi Enofc1c7b92010-03-19 23:18:02 +0900605 if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) {
Andreas Huber608d77b2010-06-23 16:40:57 -0700606 return FILE_EXTS[i].playertype;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800607 }
608 }
609 }
610
Andreas Huber47f59cf2009-08-07 09:30:32 -0700611 return getDefaultPlayerType();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800612}
613
614static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
615 notify_callback_f notifyFunc)
616{
617 sp<MediaPlayerBase> p;
618 switch (playerType) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800619 case SONIVOX_PLAYER:
620 LOGV(" create MidiFile");
621 p = new MidiFile();
622 break;
Andreas Huber20111aa2009-07-14 16:56:47 -0700623 case STAGEFRIGHT_PLAYER:
624 LOGV(" create StagefrightPlayer");
625 p = new StagefrightPlayer;
626 break;
Andreas Huberf9334412010-12-15 15:17:42 -0800627 case NU_PLAYER:
628 LOGV(" create NuPlayer");
629 p = new NuPlayerDriver;
630 break;
Nicolas Catania14d27472009-07-13 14:37:49 -0700631 case TEST_PLAYER:
632 LOGV("Create Test Player stub");
633 p = new TestPlayerStub();
634 break;
Mike J. Chen9b153be2011-08-15 13:24:13 -0700635 case AAH_RX_PLAYER:
636 LOGV(" create A@H RX Player");
637 p = createAAH_RXPlayer();
638 break;
639 case AAH_TX_PLAYER:
640 LOGV(" create A@H TX Player");
641 p = createAAH_TXPlayer();
642 break;
James Dong30d713a2010-11-10 18:42:40 -0800643 default:
644 LOGE("Unknown player type: %d", playerType);
645 return NULL;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800646 }
647 if (p != NULL) {
648 if (p->initCheck() == NO_ERROR) {
649 p->setNotifyCallback(cookie, notifyFunc);
650 } else {
651 p.clear();
652 }
653 }
654 if (p == NULL) {
655 LOGE("Failed to create player object");
656 }
657 return p;
658}
659
660sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
661{
662 // determine if we have the right player type
663 sp<MediaPlayerBase> p = mPlayer;
664 if ((p != NULL) && (p->playerType() != playerType)) {
665 LOGV("delete player");
666 p.clear();
667 }
668 if (p == NULL) {
669 p = android::createPlayer(playerType, this, notify);
670 }
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700671
Jason Simmonsdb29e522011-08-12 13:46:55 -0700672 if (p != NULL) {
673 p->setUID(mUID);
674 }
Andreas Huber9b80c2b2011-06-30 15:47:02 -0700675
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800676 return p;
677}
678
Andreas Huber2db84552010-01-28 11:19:57 -0800679status_t MediaPlayerService::Client::setDataSource(
680 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800681{
682 LOGV("setDataSource(%s)", url);
683 if (url == NULL)
684 return UNKNOWN_ERROR;
685
Dave Burked681bbb2011-08-30 14:39:17 +0100686 if ((strncmp(url, "http://", 7) == 0) ||
687 (strncmp(url, "https://", 8) == 0) ||
688 (strncmp(url, "rtsp://", 7) == 0)) {
689 if (!checkPermission("android.permission.INTERNET")) {
690 return PERMISSION_DENIED;
691 }
692 }
693
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800694 if (strncmp(url, "content://", 10) == 0) {
695 // get a filedescriptor for the content Uri and
696 // pass it to the setDataSource(fd) method
697
698 String16 url16(url);
699 int fd = android::openContentProviderFile(url16);
700 if (fd < 0)
701 {
702 LOGE("Couldn't open fd for %s", url);
703 return UNKNOWN_ERROR;
704 }
705 setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
706 close(fd);
707 return mStatus;
708 } else {
709 player_type playerType = getPlayerType(url);
710 LOGV("player type = %d", playerType);
711
712 // create the right type of player
713 sp<MediaPlayerBase> p = createPlayer(playerType);
714 if (p == NULL) return NO_INIT;
715
716 if (!p->hardwareOutput()) {
Eric Laurenta514bdb2010-06-21 09:27:30 -0700717 mAudioOutput = new AudioOutput(mAudioSessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800718 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
719 }
720
721 // now set data source
722 LOGV(" setDataSource");
Andreas Huber2db84552010-01-28 11:19:57 -0800723 mStatus = p->setDataSource(url, headers);
Nicolas Catania14d27472009-07-13 14:37:49 -0700724 if (mStatus == NO_ERROR) {
725 mPlayer = p;
726 } else {
727 LOGE(" error: %d", mStatus);
728 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800729 return mStatus;
730 }
731}
732
733status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
734{
735 LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
736 struct stat sb;
737 int ret = fstat(fd, &sb);
738 if (ret != 0) {
739 LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
740 return UNKNOWN_ERROR;
741 }
742
743 LOGV("st_dev = %llu", sb.st_dev);
744 LOGV("st_mode = %u", sb.st_mode);
745 LOGV("st_uid = %lu", sb.st_uid);
746 LOGV("st_gid = %lu", sb.st_gid);
747 LOGV("st_size = %llu", sb.st_size);
748
749 if (offset >= sb.st_size) {
750 LOGE("offset error");
751 ::close(fd);
752 return UNKNOWN_ERROR;
753 }
754 if (offset + length > sb.st_size) {
755 length = sb.st_size - offset;
756 LOGV("calculated length = %lld", length);
757 }
758
759 player_type playerType = getPlayerType(fd, offset, length);
760 LOGV("player type = %d", playerType);
761
762 // create the right type of player
763 sp<MediaPlayerBase> p = createPlayer(playerType);
764 if (p == NULL) return NO_INIT;
765
766 if (!p->hardwareOutput()) {
Eric Laurenta514bdb2010-06-21 09:27:30 -0700767 mAudioOutput = new AudioOutput(mAudioSessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800768 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
769 }
770
771 // now set data source
772 mStatus = p->setDataSource(fd, offset, length);
773 if (mStatus == NO_ERROR) mPlayer = p;
Dave Burked681bbb2011-08-30 14:39:17 +0100774
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800775 return mStatus;
776}
777
Andreas Hubere2b10282010-11-23 11:41:34 -0800778status_t MediaPlayerService::Client::setDataSource(
779 const sp<IStreamSource> &source) {
780 // create the right type of player
Andreas Huberf9334412010-12-15 15:17:42 -0800781 sp<MediaPlayerBase> p = createPlayer(NU_PLAYER);
Andreas Hubere2b10282010-11-23 11:41:34 -0800782
783 if (p == NULL) {
784 return NO_INIT;
785 }
786
787 if (!p->hardwareOutput()) {
788 mAudioOutput = new AudioOutput(mAudioSessionId);
789 static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
790 }
791
792 // now set data source
793 mStatus = p->setDataSource(source);
794
795 if (mStatus == OK) {
796 mPlayer = p;
797 }
798
799 return mStatus;
800}
801
Andreas Huber5daeb122010-08-16 08:49:37 -0700802status_t MediaPlayerService::Client::setVideoSurface(const sp<Surface>& surface)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800803{
804 LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get());
805 sp<MediaPlayerBase> p = getPlayer();
806 if (p == 0) return UNKNOWN_ERROR;
807 return p->setVideoSurface(surface);
808}
809
Glenn Kasten11731182011-02-08 17:26:17 -0800810status_t MediaPlayerService::Client::setVideoSurfaceTexture(
811 const sp<ISurfaceTexture>& surfaceTexture)
812{
813 LOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, surfaceTexture.get());
814 sp<MediaPlayerBase> p = getPlayer();
815 if (p == 0) return UNKNOWN_ERROR;
816 return p->setVideoSurfaceTexture(surfaceTexture);
817}
818
Nicolas Catania1d187f12009-05-12 23:25:55 -0700819status_t MediaPlayerService::Client::invoke(const Parcel& request,
820 Parcel *reply)
821{
822 sp<MediaPlayerBase> p = getPlayer();
823 if (p == NULL) return UNKNOWN_ERROR;
824 return p->invoke(request, reply);
825}
826
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700827// This call doesn't need to access the native player.
828status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
829{
830 status_t status;
nikoa64c8c72009-07-20 15:07:26 -0700831 media::Metadata::Filter allow, drop;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700832
Nicolas Catania48290382009-07-10 13:53:06 -0700833 if (unmarshallFilter(filter, &allow, &status) &&
834 unmarshallFilter(filter, &drop, &status)) {
835 Mutex::Autolock lock(mLock);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700836
837 mMetadataAllow = allow;
838 mMetadataDrop = drop;
839 }
840 return status;
841}
842
Nicolas Catania48290382009-07-10 13:53:06 -0700843status_t MediaPlayerService::Client::getMetadata(
844 bool update_only, bool apply_filter, Parcel *reply)
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700845{
nikoa64c8c72009-07-20 15:07:26 -0700846 sp<MediaPlayerBase> player = getPlayer();
847 if (player == 0) return UNKNOWN_ERROR;
Nicolas Catania48290382009-07-10 13:53:06 -0700848
nikod608a812009-07-16 16:39:53 -0700849 status_t status;
850 // Placeholder for the return code, updated by the caller.
851 reply->writeInt32(-1);
852
nikoa64c8c72009-07-20 15:07:26 -0700853 media::Metadata::Filter ids;
Nicolas Catania48290382009-07-10 13:53:06 -0700854
855 // We don't block notifications while we fetch the data. We clear
856 // mMetadataUpdated first so we don't lose notifications happening
857 // during the rest of this call.
858 {
859 Mutex::Autolock lock(mLock);
860 if (update_only) {
nikod608a812009-07-16 16:39:53 -0700861 ids = mMetadataUpdated;
Nicolas Catania48290382009-07-10 13:53:06 -0700862 }
863 mMetadataUpdated.clear();
864 }
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700865
nikoa64c8c72009-07-20 15:07:26 -0700866 media::Metadata metadata(reply);
Nicolas Catania48290382009-07-10 13:53:06 -0700867
nikoa64c8c72009-07-20 15:07:26 -0700868 metadata.appendHeader();
869 status = player->getMetadata(ids, reply);
nikod608a812009-07-16 16:39:53 -0700870
871 if (status != OK) {
nikoa64c8c72009-07-20 15:07:26 -0700872 metadata.resetParcel();
nikod608a812009-07-16 16:39:53 -0700873 LOGE("getMetadata failed %d", status);
874 return status;
875 }
876
877 // FIXME: Implement filtering on the result. Not critical since
878 // filtering takes place on the update notifications already. This
879 // would be when all the metadata are fetch and a filter is set.
880
nikod608a812009-07-16 16:39:53 -0700881 // Everything is fine, update the metadata length.
nikoa64c8c72009-07-20 15:07:26 -0700882 metadata.updateLength();
nikod608a812009-07-16 16:39:53 -0700883 return OK;
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700884}
885
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800886status_t MediaPlayerService::Client::prepareAsync()
887{
888 LOGV("[%d] prepareAsync", mConnId);
889 sp<MediaPlayerBase> p = getPlayer();
890 if (p == 0) return UNKNOWN_ERROR;
891 status_t ret = p->prepareAsync();
892#if CALLBACK_ANTAGONIZER
893 LOGD("start Antagonizer");
894 if (ret == NO_ERROR) mAntagonizer->start();
895#endif
896 return ret;
897}
898
899status_t MediaPlayerService::Client::start()
900{
901 LOGV("[%d] start", mConnId);
902 sp<MediaPlayerBase> p = getPlayer();
903 if (p == 0) return UNKNOWN_ERROR;
904 p->setLooping(mLoop);
905 return p->start();
906}
907
908status_t MediaPlayerService::Client::stop()
909{
910 LOGV("[%d] stop", mConnId);
911 sp<MediaPlayerBase> p = getPlayer();
912 if (p == 0) return UNKNOWN_ERROR;
913 return p->stop();
914}
915
916status_t MediaPlayerService::Client::pause()
917{
918 LOGV("[%d] pause", mConnId);
919 sp<MediaPlayerBase> p = getPlayer();
920 if (p == 0) return UNKNOWN_ERROR;
921 return p->pause();
922}
923
924status_t MediaPlayerService::Client::isPlaying(bool* state)
925{
926 *state = false;
927 sp<MediaPlayerBase> p = getPlayer();
928 if (p == 0) return UNKNOWN_ERROR;
929 *state = p->isPlaying();
930 LOGV("[%d] isPlaying: %d", mConnId, *state);
931 return NO_ERROR;
932}
933
934status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
935{
936 LOGV("getCurrentPosition");
937 sp<MediaPlayerBase> p = getPlayer();
938 if (p == 0) return UNKNOWN_ERROR;
939 status_t ret = p->getCurrentPosition(msec);
940 if (ret == NO_ERROR) {
941 LOGV("[%d] getCurrentPosition = %d", mConnId, *msec);
942 } else {
943 LOGE("getCurrentPosition returned %d", ret);
944 }
945 return ret;
946}
947
948status_t MediaPlayerService::Client::getDuration(int *msec)
949{
950 LOGV("getDuration");
951 sp<MediaPlayerBase> p = getPlayer();
952 if (p == 0) return UNKNOWN_ERROR;
953 status_t ret = p->getDuration(msec);
954 if (ret == NO_ERROR) {
955 LOGV("[%d] getDuration = %d", mConnId, *msec);
956 } else {
957 LOGE("getDuration returned %d", ret);
958 }
959 return ret;
960}
961
962status_t MediaPlayerService::Client::seekTo(int msec)
963{
964 LOGV("[%d] seekTo(%d)", mConnId, msec);
965 sp<MediaPlayerBase> p = getPlayer();
966 if (p == 0) return UNKNOWN_ERROR;
967 return p->seekTo(msec);
968}
969
970status_t MediaPlayerService::Client::reset()
971{
972 LOGV("[%d] reset", mConnId);
973 sp<MediaPlayerBase> p = getPlayer();
974 if (p == 0) return UNKNOWN_ERROR;
975 return p->reset();
976}
977
978status_t MediaPlayerService::Client::setAudioStreamType(int type)
979{
980 LOGV("[%d] setAudioStreamType(%d)", mConnId, type);
981 // TODO: for hardware output, call player instead
982 Mutex::Autolock l(mLock);
983 if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
984 return NO_ERROR;
985}
986
987status_t MediaPlayerService::Client::setLooping(int loop)
988{
989 LOGV("[%d] setLooping(%d)", mConnId, loop);
990 mLoop = loop;
991 sp<MediaPlayerBase> p = getPlayer();
992 if (p != 0) return p->setLooping(loop);
993 return NO_ERROR;
994}
995
996status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
997{
998 LOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
Mike J. Chen9b153be2011-08-15 13:24:13 -0700999
1000 // for hardware output, call player instead
1001 sp<MediaPlayerBase> p = getPlayer();
1002 {
1003 Mutex::Autolock l(mLock);
1004 if (p != 0 && p->hardwareOutput()) {
1005 MediaPlayerHWInterface* hwp =
1006 reinterpret_cast<MediaPlayerHWInterface*>(p.get());
1007 return hwp->setVolume(leftVolume, rightVolume);
1008 } else {
1009 if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
1010 return NO_ERROR;
1011 }
1012 }
1013
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001014 return NO_ERROR;
1015}
1016
Eric Laurent2beeb502010-07-16 07:43:46 -07001017status_t MediaPlayerService::Client::setAuxEffectSendLevel(float level)
1018{
1019 LOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
1020 Mutex::Autolock l(mLock);
1021 if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
1022 return NO_ERROR;
1023}
1024
1025status_t MediaPlayerService::Client::attachAuxEffect(int effectId)
1026{
1027 LOGV("[%d] attachAuxEffect(%d)", mConnId, effectId);
1028 Mutex::Autolock l(mLock);
1029 if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId);
1030 return NO_ERROR;
1031}
Nicolas Catania48290382009-07-10 13:53:06 -07001032
Gloria Wang4f9e47f2011-04-25 17:28:22 -07001033status_t MediaPlayerService::Client::setParameter(int key, const Parcel &request) {
1034 LOGV("[%d] setParameter(%d)", mConnId, key);
1035 sp<MediaPlayerBase> p = getPlayer();
1036 if (p == 0) return UNKNOWN_ERROR;
1037 return p->setParameter(key, request);
1038}
1039
1040status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) {
1041 LOGV("[%d] getParameter(%d)", mConnId, key);
1042 sp<MediaPlayerBase> p = getPlayer();
1043 if (p == 0) return UNKNOWN_ERROR;
1044 return p->getParameter(key, reply);
1045}
1046
Gloria Wangb483c472011-04-11 17:23:27 -07001047void MediaPlayerService::Client::notify(
1048 void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001049{
1050 Client* client = static_cast<Client*>(cookie);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001051
1052 if (MEDIA_INFO == msg &&
Nicolas Catania48290382009-07-10 13:53:06 -07001053 MEDIA_INFO_METADATA_UPDATE == ext1) {
nikoa64c8c72009-07-20 15:07:26 -07001054 const media::Metadata::Type metadata_type = ext2;
Nicolas Catania48290382009-07-10 13:53:06 -07001055
1056 if(client->shouldDropMetadata(metadata_type)) {
1057 return;
1058 }
1059
1060 // Update the list of metadata that have changed. getMetadata
1061 // also access mMetadataUpdated and clears it.
1062 client->addNewMetadataUpdate(metadata_type);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001063 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001064 LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
Gloria Wangb483c472011-04-11 17:23:27 -07001065 client->mClient->notify(msg, ext1, ext2, obj);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001066}
1067
Nicolas Catania48290382009-07-10 13:53:06 -07001068
nikoa64c8c72009-07-20 15:07:26 -07001069bool MediaPlayerService::Client::shouldDropMetadata(media::Metadata::Type code) const
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001070{
Nicolas Catania48290382009-07-10 13:53:06 -07001071 Mutex::Autolock lock(mLock);
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001072
Nicolas Catania48290382009-07-10 13:53:06 -07001073 if (findMetadata(mMetadataDrop, code)) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001074 return true;
1075 }
1076
Nicolas Catania48290382009-07-10 13:53:06 -07001077 if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001078 return false;
Nicolas Catania48290382009-07-10 13:53:06 -07001079 } else {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -07001080 return true;
1081 }
1082}
1083
Nicolas Catania48290382009-07-10 13:53:06 -07001084
nikoa64c8c72009-07-20 15:07:26 -07001085void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
Nicolas Catania48290382009-07-10 13:53:06 -07001086 Mutex::Autolock lock(mLock);
1087 if (mMetadataUpdated.indexOf(metadata_type) < 0) {
1088 mMetadataUpdated.add(metadata_type);
1089 }
1090}
1091
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001092#if CALLBACK_ANTAGONIZER
1093const int Antagonizer::interval = 10000; // 10 msecs
1094
1095Antagonizer::Antagonizer(notify_callback_f cb, void* client) :
1096 mExit(false), mActive(false), mClient(client), mCb(cb)
1097{
1098 createThread(callbackThread, this);
1099}
1100
1101void Antagonizer::kill()
1102{
1103 Mutex::Autolock _l(mLock);
1104 mActive = false;
1105 mExit = true;
1106 mCondition.wait(mLock);
1107}
1108
1109int Antagonizer::callbackThread(void* user)
1110{
1111 LOGD("Antagonizer started");
1112 Antagonizer* p = reinterpret_cast<Antagonizer*>(user);
1113 while (!p->mExit) {
1114 if (p->mActive) {
1115 LOGV("send event");
1116 p->mCb(p->mClient, 0, 0, 0);
1117 }
1118 usleep(interval);
1119 }
1120 Mutex::Autolock _l(p->mLock);
1121 p->mCondition.signal();
1122 LOGD("Antagonizer stopped");
1123 return 0;
1124}
1125#endif
1126
1127static size_t kDefaultHeapSize = 1024 * 1024; // 1MB
1128
1129sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
1130{
1131 LOGV("decode(%s)", url);
1132 sp<MemoryBase> mem;
1133 sp<MediaPlayerBase> player;
1134
1135 // Protect our precious, precious DRMd ringtones by only allowing
1136 // decoding of http, but not filesystem paths or content Uris.
1137 // If the application wants to decode those, it should open a
1138 // filedescriptor for them and use that.
1139 if (url != NULL && strncmp(url, "http://", 7) != 0) {
1140 LOGD("Can't decode %s by path, use filedescriptor instead", url);
1141 return mem;
1142 }
1143
1144 player_type playerType = getPlayerType(url);
1145 LOGV("player type = %d", playerType);
1146
1147 // create the right type of player
1148 sp<AudioCache> cache = new AudioCache(url);
1149 player = android::createPlayer(playerType, cache.get(), cache->notify);
1150 if (player == NULL) goto Exit;
1151 if (player->hardwareOutput()) goto Exit;
1152
1153 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1154
1155 // set data source
1156 if (player->setDataSource(url) != NO_ERROR) goto Exit;
1157
1158 LOGV("prepare");
1159 player->prepareAsync();
1160
1161 LOGV("wait for prepare");
1162 if (cache->wait() != NO_ERROR) goto Exit;
1163
1164 LOGV("start");
1165 player->start();
1166
1167 LOGV("wait for playback complete");
1168 if (cache->wait() != NO_ERROR) goto Exit;
1169
1170 mem = new MemoryBase(cache->getHeap(), 0, cache->size());
1171 *pSampleRate = cache->sampleRate();
1172 *pNumChannels = cache->channelCount();
Jean-Michel Trivi0d255b22011-05-24 15:53:33 -07001173 *pFormat = (int)cache->format();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001174 LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
1175
1176Exit:
1177 if (player != 0) player->reset();
1178 return mem;
1179}
1180
1181sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
1182{
1183 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
1184 sp<MemoryBase> mem;
1185 sp<MediaPlayerBase> player;
1186
1187 player_type playerType = getPlayerType(fd, offset, length);
1188 LOGV("player type = %d", playerType);
1189
1190 // create the right type of player
1191 sp<AudioCache> cache = new AudioCache("decode_fd");
1192 player = android::createPlayer(playerType, cache.get(), cache->notify);
1193 if (player == NULL) goto Exit;
1194 if (player->hardwareOutput()) goto Exit;
1195
1196 static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
1197
1198 // set data source
1199 if (player->setDataSource(fd, offset, length) != NO_ERROR) goto Exit;
1200
1201 LOGV("prepare");
1202 player->prepareAsync();
1203
1204 LOGV("wait for prepare");
1205 if (cache->wait() != NO_ERROR) goto Exit;
1206
1207 LOGV("start");
1208 player->start();
1209
1210 LOGV("wait for playback complete");
1211 if (cache->wait() != NO_ERROR) goto Exit;
1212
1213 mem = new MemoryBase(cache->getHeap(), 0, cache->size());
1214 *pSampleRate = cache->sampleRate();
1215 *pNumChannels = cache->channelCount();
1216 *pFormat = cache->format();
1217 LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
1218
1219Exit:
1220 if (player != 0) player->reset();
1221 ::close(fd);
1222 return mem;
1223}
1224
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001225
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001226#undef LOG_TAG
1227#define LOG_TAG "AudioSink"
Eric Laurenta514bdb2010-06-21 09:27:30 -07001228MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
Andreas Huber20111aa2009-07-14 16:56:47 -07001229 : mCallback(NULL),
Eric Laurenta514bdb2010-06-21 09:27:30 -07001230 mCallbackCookie(NULL),
1231 mSessionId(sessionId) {
1232 LOGV("AudioOutput(%d)", sessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001233 mTrack = 0;
Dima Zavinfce7a472011-04-19 22:30:36 -07001234 mStreamType = AUDIO_STREAM_MUSIC;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001235 mLeftVolume = 1.0;
1236 mRightVolume = 1.0;
1237 mLatency = 0;
1238 mMsecsPerFrame = 0;
Eric Laurent2beeb502010-07-16 07:43:46 -07001239 mAuxEffectId = 0;
1240 mSendLevel = 0.0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001241 setMinBufferCount();
1242}
1243
1244MediaPlayerService::AudioOutput::~AudioOutput()
1245{
1246 close();
1247}
1248
1249void MediaPlayerService::AudioOutput::setMinBufferCount()
1250{
1251 char value[PROPERTY_VALUE_MAX];
1252 if (property_get("ro.kernel.qemu", value, 0)) {
1253 mIsOnEmulator = true;
1254 mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
1255 }
1256}
1257
1258bool MediaPlayerService::AudioOutput::isOnEmulator()
1259{
1260 setMinBufferCount();
1261 return mIsOnEmulator;
1262}
1263
1264int MediaPlayerService::AudioOutput::getMinBufferCount()
1265{
1266 setMinBufferCount();
1267 return mMinBufferCount;
1268}
1269
1270ssize_t MediaPlayerService::AudioOutput::bufferSize() const
1271{
1272 if (mTrack == 0) return NO_INIT;
1273 return mTrack->frameCount() * frameSize();
1274}
1275
1276ssize_t MediaPlayerService::AudioOutput::frameCount() const
1277{
1278 if (mTrack == 0) return NO_INIT;
1279 return mTrack->frameCount();
1280}
1281
1282ssize_t MediaPlayerService::AudioOutput::channelCount() const
1283{
1284 if (mTrack == 0) return NO_INIT;
1285 return mTrack->channelCount();
1286}
1287
1288ssize_t MediaPlayerService::AudioOutput::frameSize() const
1289{
1290 if (mTrack == 0) return NO_INIT;
1291 return mTrack->frameSize();
1292}
1293
1294uint32_t MediaPlayerService::AudioOutput::latency () const
1295{
1296 return mLatency;
1297}
1298
1299float MediaPlayerService::AudioOutput::msecsPerFrame() const
1300{
1301 return mMsecsPerFrame;
1302}
1303
Eric Laurent342e9cf2010-01-19 17:37:09 -08001304status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position)
1305{
1306 if (mTrack == 0) return NO_INIT;
1307 return mTrack->getPosition(position);
1308}
1309
Andreas Huber20111aa2009-07-14 16:56:47 -07001310status_t MediaPlayerService::AudioOutput::open(
1311 uint32_t sampleRate, int channelCount, int format, int bufferCount,
1312 AudioCallback cb, void *cookie)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001313{
Andreas Huber20111aa2009-07-14 16:56:47 -07001314 mCallback = cb;
1315 mCallbackCookie = cookie;
1316
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001317 // Check argument "bufferCount" against the mininum buffer count
1318 if (bufferCount < mMinBufferCount) {
1319 LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
1320 bufferCount = mMinBufferCount;
1321
1322 }
Eric Laurenta514bdb2010-06-21 09:27:30 -07001323 LOGV("open(%u, %d, %d, %d, %d)", sampleRate, channelCount, format, bufferCount,mSessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001324 if (mTrack) close();
1325 int afSampleRate;
1326 int afFrameCount;
1327 int frameCount;
1328
1329 if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
1330 return NO_INIT;
1331 }
1332 if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
1333 return NO_INIT;
1334 }
1335
1336 frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
Andreas Huber20111aa2009-07-14 16:56:47 -07001337
1338 AudioTrack *t;
1339 if (mCallback != NULL) {
1340 t = new AudioTrack(
Eric Laurentc2f1f072009-07-17 12:17:14 -07001341 mStreamType,
1342 sampleRate,
1343 format,
Dima Zavinfce7a472011-04-19 22:30:36 -07001344 (channelCount == 2) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO,
Eric Laurentc2f1f072009-07-17 12:17:14 -07001345 frameCount,
1346 0 /* flags */,
1347 CallbackWrapper,
Eric Laurenta514bdb2010-06-21 09:27:30 -07001348 this,
1349 0,
1350 mSessionId);
Andreas Huber20111aa2009-07-14 16:56:47 -07001351 } else {
1352 t = new AudioTrack(
Eric Laurentc2f1f072009-07-17 12:17:14 -07001353 mStreamType,
1354 sampleRate,
1355 format,
Dima Zavinfce7a472011-04-19 22:30:36 -07001356 (channelCount == 2) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO,
Eric Laurenta514bdb2010-06-21 09:27:30 -07001357 frameCount,
1358 0,
1359 NULL,
1360 NULL,
1361 0,
1362 mSessionId);
Andreas Huber20111aa2009-07-14 16:56:47 -07001363 }
1364
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001365 if ((t == 0) || (t->initCheck() != NO_ERROR)) {
1366 LOGE("Unable to create audio track");
1367 delete t;
1368 return NO_INIT;
1369 }
1370
1371 LOGV("setVolume");
1372 t->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -07001373
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001374 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Dave Sparks1d711f62009-12-03 10:13:32 -08001375 mLatency = t->latency();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001376 mTrack = t;
Eric Laurent2beeb502010-07-16 07:43:46 -07001377
1378 t->setAuxEffectSendLevel(mSendLevel);
1379 return t->attachAuxEffect(mAuxEffectId);;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001380}
1381
1382void MediaPlayerService::AudioOutput::start()
1383{
1384 LOGV("start");
1385 if (mTrack) {
1386 mTrack->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -07001387 mTrack->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001388 mTrack->start();
1389 }
1390}
1391
Marco Nelissen7ee8ac92010-01-12 09:23:54 -08001392
1393
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001394ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
1395{
Andreas Huber20111aa2009-07-14 16:56:47 -07001396 LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
1397
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001398 //LOGV("write(%p, %u)", buffer, size);
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001399 if (mTrack) {
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001400 ssize_t ret = mTrack->write(buffer, size);
Marco Nelissen10dbb8e2009-09-20 10:42:13 -07001401 return ret;
1402 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001403 return NO_INIT;
1404}
1405
1406void MediaPlayerService::AudioOutput::stop()
1407{
1408 LOGV("stop");
1409 if (mTrack) mTrack->stop();
1410}
1411
1412void MediaPlayerService::AudioOutput::flush()
1413{
1414 LOGV("flush");
1415 if (mTrack) mTrack->flush();
1416}
1417
1418void MediaPlayerService::AudioOutput::pause()
1419{
1420 LOGV("pause");
1421 if (mTrack) mTrack->pause();
1422}
1423
1424void MediaPlayerService::AudioOutput::close()
1425{
1426 LOGV("close");
1427 delete mTrack;
1428 mTrack = 0;
1429}
1430
1431void MediaPlayerService::AudioOutput::setVolume(float left, float right)
1432{
1433 LOGV("setVolume(%f, %f)", left, right);
1434 mLeftVolume = left;
1435 mRightVolume = right;
1436 if (mTrack) {
1437 mTrack->setVolume(left, right);
1438 }
1439}
1440
Eric Laurent2beeb502010-07-16 07:43:46 -07001441status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
1442{
1443 LOGV("setAuxEffectSendLevel(%f)", level);
1444 mSendLevel = level;
1445 if (mTrack) {
1446 return mTrack->setAuxEffectSendLevel(level);
1447 }
1448 return NO_ERROR;
1449}
1450
1451status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
1452{
1453 LOGV("attachAuxEffect(%d)", effectId);
1454 mAuxEffectId = effectId;
1455 if (mTrack) {
1456 return mTrack->attachAuxEffect(effectId);
1457 }
1458 return NO_ERROR;
1459}
1460
Andreas Huber20111aa2009-07-14 16:56:47 -07001461// static
1462void MediaPlayerService::AudioOutput::CallbackWrapper(
Glenn Kastend217a8c2011-06-01 15:20:35 -07001463 int event, void *cookie, void *info) {
Marco Nelissen7ee8ac92010-01-12 09:23:54 -08001464 //LOGV("callbackwrapper");
Andreas Huber20111aa2009-07-14 16:56:47 -07001465 if (event != AudioTrack::EVENT_MORE_DATA) {
1466 return;
1467 }
1468
1469 AudioOutput *me = (AudioOutput *)cookie;
1470 AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
1471
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001472 size_t actualSize = (*me->mCallback)(
Andreas Huber20111aa2009-07-14 16:56:47 -07001473 me, buffer->raw, buffer->size, me->mCallbackCookie);
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001474
Andreas Huber51c1e0e2011-04-04 11:43:40 -07001475 if (actualSize == 0 && buffer->size > 0) {
1476 // We've reached EOS but the audio track is not stopped yet,
1477 // keep playing silence.
Andreas Huber2e8ffaf2010-02-18 16:45:13 -08001478
Andreas Huber51c1e0e2011-04-04 11:43:40 -07001479 memset(buffer->raw, 0, buffer->size);
1480 actualSize = buffer->size;
1481 }
1482
1483 buffer->size = actualSize;
Andreas Huber20111aa2009-07-14 16:56:47 -07001484}
1485
Eric Laurent8c563ed2010-10-07 18:23:03 -07001486int MediaPlayerService::AudioOutput::getSessionId()
1487{
1488 return mSessionId;
1489}
1490
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001491#undef LOG_TAG
1492#define LOG_TAG "AudioCache"
1493MediaPlayerService::AudioCache::AudioCache(const char* name) :
1494 mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
1495 mError(NO_ERROR), mCommandComplete(false)
1496{
1497 // create ashmem heap
1498 mHeap = new MemoryHeapBase(kDefaultHeapSize, 0, name);
1499}
1500
1501uint32_t MediaPlayerService::AudioCache::latency () const
1502{
1503 return 0;
1504}
1505
1506float MediaPlayerService::AudioCache::msecsPerFrame() const
1507{
1508 return mMsecsPerFrame;
1509}
1510
Eric Laurent342e9cf2010-01-19 17:37:09 -08001511status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position)
1512{
1513 if (position == 0) return BAD_VALUE;
1514 *position = mSize;
1515 return NO_ERROR;
1516}
1517
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001518////////////////////////////////////////////////////////////////////////////////
1519
1520struct CallbackThread : public Thread {
1521 CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink,
1522 MediaPlayerBase::AudioSink::AudioCallback cb,
1523 void *cookie);
1524
1525protected:
1526 virtual ~CallbackThread();
1527
1528 virtual bool threadLoop();
1529
1530private:
1531 wp<MediaPlayerBase::AudioSink> mSink;
1532 MediaPlayerBase::AudioSink::AudioCallback mCallback;
1533 void *mCookie;
1534 void *mBuffer;
1535 size_t mBufferSize;
1536
1537 CallbackThread(const CallbackThread &);
1538 CallbackThread &operator=(const CallbackThread &);
1539};
1540
1541CallbackThread::CallbackThread(
1542 const wp<MediaPlayerBase::AudioSink> &sink,
1543 MediaPlayerBase::AudioSink::AudioCallback cb,
1544 void *cookie)
1545 : mSink(sink),
1546 mCallback(cb),
1547 mCookie(cookie),
1548 mBuffer(NULL),
1549 mBufferSize(0) {
1550}
1551
1552CallbackThread::~CallbackThread() {
1553 if (mBuffer) {
1554 free(mBuffer);
1555 mBuffer = NULL;
1556 }
1557}
1558
1559bool CallbackThread::threadLoop() {
1560 sp<MediaPlayerBase::AudioSink> sink = mSink.promote();
1561 if (sink == NULL) {
1562 return false;
1563 }
1564
1565 if (mBuffer == NULL) {
1566 mBufferSize = sink->bufferSize();
1567 mBuffer = malloc(mBufferSize);
1568 }
1569
1570 size_t actualSize =
1571 (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie);
1572
1573 if (actualSize > 0) {
1574 sink->write(mBuffer, actualSize);
1575 }
1576
1577 return true;
1578}
1579
1580////////////////////////////////////////////////////////////////////////////////
1581
Andreas Huber20111aa2009-07-14 16:56:47 -07001582status_t MediaPlayerService::AudioCache::open(
1583 uint32_t sampleRate, int channelCount, int format, int bufferCount,
1584 AudioCallback cb, void *cookie)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001585{
Dave Sparks8eb80112009-12-09 20:20:26 -08001586 LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
Dave Sparks8eb80112009-12-09 20:20:26 -08001587 if (mHeap->getHeapID() < 0) {
1588 return NO_INIT;
1589 }
Andreas Huber20111aa2009-07-14 16:56:47 -07001590
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001591 mSampleRate = sampleRate;
1592 mChannelCount = (uint16_t)channelCount;
1593 mFormat = (uint16_t)format;
1594 mMsecsPerFrame = 1.e3 / (float) sampleRate;
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001595
1596 if (cb != NULL) {
1597 mCallbackThread = new CallbackThread(this, cb, cookie);
1598 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001599 return NO_ERROR;
1600}
1601
Andreas Huber7d5b8a72010-02-09 16:59:18 -08001602void MediaPlayerService::AudioCache::start() {
1603 if (mCallbackThread != NULL) {
1604 mCallbackThread->run("AudioCache callback");
1605 }
1606}
1607
1608void MediaPlayerService::AudioCache::stop() {
1609 if (mCallbackThread != NULL) {
1610 mCallbackThread->requestExitAndWait();
1611 }
1612}
1613
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001614ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
1615{
1616 LOGV("write(%p, %u)", buffer, size);
1617 if ((buffer == 0) || (size == 0)) return size;
1618
1619 uint8_t* p = static_cast<uint8_t*>(mHeap->getBase());
1620 if (p == NULL) return NO_INIT;
1621 p += mSize;
1622 LOGV("memcpy(%p, %p, %u)", p, buffer, size);
1623 if (mSize + size > mHeap->getSize()) {
1624 LOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
1625 size = mHeap->getSize() - mSize;
1626 }
1627 memcpy(p, buffer, size);
1628 mSize += size;
1629 return size;
1630}
1631
1632// call with lock held
1633status_t MediaPlayerService::AudioCache::wait()
1634{
1635 Mutex::Autolock lock(mLock);
Dave Sparks4bbc0ba2010-03-01 19:29:58 -08001636 while (!mCommandComplete) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001637 mSignal.wait(mLock);
1638 }
1639 mCommandComplete = false;
1640
1641 if (mError == NO_ERROR) {
1642 LOGV("wait - success");
1643 } else {
1644 LOGV("wait - error");
1645 }
1646 return mError;
1647}
1648
Gloria Wangb483c472011-04-11 17:23:27 -07001649void MediaPlayerService::AudioCache::notify(
1650 void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001651{
1652 LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
1653 AudioCache* p = static_cast<AudioCache*>(cookie);
1654
1655 // ignore buffering messages
Dave Sparks8eb80112009-12-09 20:20:26 -08001656 switch (msg)
1657 {
1658 case MEDIA_ERROR:
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001659 LOGE("Error %d, %d occurred", ext1, ext2);
1660 p->mError = ext1;
Dave Sparks8eb80112009-12-09 20:20:26 -08001661 break;
1662 case MEDIA_PREPARED:
1663 LOGV("prepared");
1664 break;
1665 case MEDIA_PLAYBACK_COMPLETE:
1666 LOGV("playback complete");
1667 break;
1668 default:
1669 LOGV("ignored");
1670 return;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001671 }
1672
1673 // wake up thread
Dave Sparksfe4c6f02010-03-02 12:56:37 -08001674 Mutex::Autolock lock(p->mLock);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001675 p->mCommandComplete = true;
1676 p->mSignal.signal();
1677}
1678
Eric Laurent8c563ed2010-10-07 18:23:03 -07001679int MediaPlayerService::AudioCache::getSessionId()
1680{
1681 return 0;
1682}
1683
Gloria Wang7cf180c2011-02-19 18:37:57 -08001684void MediaPlayerService::addBatteryData(uint32_t params)
1685{
1686 Mutex::Autolock lock(mLock);
Gloria Wang9ee159b2011-02-24 14:51:45 -08001687
1688 int32_t time = systemTime() / 1000000L;
1689
1690 // change audio output devices. This notification comes from AudioFlinger
1691 if ((params & kBatteryDataSpeakerOn)
1692 || (params & kBatteryDataOtherAudioDeviceOn)) {
1693
1694 int deviceOn[NUM_AUDIO_DEVICES];
1695 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1696 deviceOn[i] = 0;
1697 }
1698
1699 if ((params & kBatteryDataSpeakerOn)
1700 && (params & kBatteryDataOtherAudioDeviceOn)) {
1701 deviceOn[SPEAKER_AND_OTHER] = 1;
1702 } else if (params & kBatteryDataSpeakerOn) {
1703 deviceOn[SPEAKER] = 1;
1704 } else {
1705 deviceOn[OTHER_AUDIO_DEVICE] = 1;
1706 }
1707
1708 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1709 if (mBatteryAudio.deviceOn[i] != deviceOn[i]){
1710
1711 if (mBatteryAudio.refCount > 0) { // if playing audio
1712 if (!deviceOn[i]) {
1713 mBatteryAudio.lastTime[i] += time;
1714 mBatteryAudio.totalTime[i] += mBatteryAudio.lastTime[i];
1715 mBatteryAudio.lastTime[i] = 0;
1716 } else {
1717 mBatteryAudio.lastTime[i] = 0 - time;
1718 }
1719 }
1720
1721 mBatteryAudio.deviceOn[i] = deviceOn[i];
1722 }
1723 }
1724 return;
1725 }
1726
1727 // an sudio stream is started
1728 if (params & kBatteryDataAudioFlingerStart) {
1729 // record the start time only if currently no other audio
1730 // is being played
1731 if (mBatteryAudio.refCount == 0) {
1732 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1733 if (mBatteryAudio.deviceOn[i]) {
1734 mBatteryAudio.lastTime[i] -= time;
1735 }
1736 }
1737 }
1738
1739 mBatteryAudio.refCount ++;
1740 return;
1741
1742 } else if (params & kBatteryDataAudioFlingerStop) {
1743 if (mBatteryAudio.refCount <= 0) {
1744 LOGW("Battery track warning: refCount is <= 0");
1745 return;
1746 }
1747
1748 // record the stop time only if currently this is the only
1749 // audio being played
1750 if (mBatteryAudio.refCount == 1) {
1751 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1752 if (mBatteryAudio.deviceOn[i]) {
1753 mBatteryAudio.lastTime[i] += time;
1754 mBatteryAudio.totalTime[i] += mBatteryAudio.lastTime[i];
1755 mBatteryAudio.lastTime[i] = 0;
1756 }
1757 }
1758 }
1759
1760 mBatteryAudio.refCount --;
1761 return;
1762 }
1763
Gloria Wang7cf180c2011-02-19 18:37:57 -08001764 int uid = IPCThreadState::self()->getCallingUid();
1765 if (uid == AID_MEDIA) {
1766 return;
1767 }
1768 int index = mBatteryData.indexOfKey(uid);
Gloria Wang7cf180c2011-02-19 18:37:57 -08001769
1770 if (index < 0) { // create a new entry for this UID
1771 BatteryUsageInfo info;
1772 info.audioTotalTime = 0;
1773 info.videoTotalTime = 0;
1774 info.audioLastTime = 0;
1775 info.videoLastTime = 0;
1776 info.refCount = 0;
1777
Gloria Wang9ee159b2011-02-24 14:51:45 -08001778 if (mBatteryData.add(uid, info) == NO_MEMORY) {
1779 LOGE("Battery track error: no memory for new app");
1780 return;
1781 }
Gloria Wang7cf180c2011-02-19 18:37:57 -08001782 }
1783
1784 BatteryUsageInfo &info = mBatteryData.editValueFor(uid);
1785
1786 if (params & kBatteryDataCodecStarted) {
1787 if (params & kBatteryDataTrackAudio) {
1788 info.audioLastTime -= time;
1789 info.refCount ++;
1790 }
1791 if (params & kBatteryDataTrackVideo) {
1792 info.videoLastTime -= time;
1793 info.refCount ++;
1794 }
1795 } else {
1796 if (info.refCount == 0) {
1797 LOGW("Battery track warning: refCount is already 0");
1798 return;
1799 } else if (info.refCount < 0) {
1800 LOGE("Battery track error: refCount < 0");
1801 mBatteryData.removeItem(uid);
1802 return;
1803 }
1804
1805 if (params & kBatteryDataTrackAudio) {
1806 info.audioLastTime += time;
1807 info.refCount --;
1808 }
1809 if (params & kBatteryDataTrackVideo) {
1810 info.videoLastTime += time;
1811 info.refCount --;
1812 }
1813
1814 // no stream is being played by this UID
1815 if (info.refCount == 0) {
1816 info.audioTotalTime += info.audioLastTime;
1817 info.audioLastTime = 0;
1818 info.videoTotalTime += info.videoLastTime;
1819 info.videoLastTime = 0;
1820 }
1821 }
1822}
1823
1824status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
1825 Mutex::Autolock lock(mLock);
Gloria Wang9ee159b2011-02-24 14:51:45 -08001826
1827 // audio output devices usage
1828 int32_t time = systemTime() / 1000000L; //in ms
1829 int32_t totalTime;
1830
1831 for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
1832 totalTime = mBatteryAudio.totalTime[i];
1833
1834 if (mBatteryAudio.deviceOn[i]
1835 && (mBatteryAudio.lastTime[i] != 0)) {
1836 int32_t tmpTime = mBatteryAudio.lastTime[i] + time;
1837 totalTime += tmpTime;
1838 }
1839
1840 reply->writeInt32(totalTime);
1841 // reset the total time
1842 mBatteryAudio.totalTime[i] = 0;
1843 }
1844
1845 // codec usage
Gloria Wang7cf180c2011-02-19 18:37:57 -08001846 BatteryUsageInfo info;
1847 int size = mBatteryData.size();
1848
1849 reply->writeInt32(size);
1850 int i = 0;
1851
1852 while (i < size) {
1853 info = mBatteryData.valueAt(i);
1854
1855 reply->writeInt32(mBatteryData.keyAt(i)); //UID
1856 reply->writeInt32(info.audioTotalTime);
1857 reply->writeInt32(info.videoTotalTime);
1858
1859 info.audioTotalTime = 0;
1860 info.videoTotalTime = 0;
1861
1862 // remove the UID entry where no stream is being played
1863 if (info.refCount <= 0) {
1864 mBatteryData.removeItemsAt(i);
1865 size --;
1866 i --;
1867 }
1868 i++;
1869 }
1870 return NO_ERROR;
1871}
nikoa64c8c72009-07-20 15:07:26 -07001872} // namespace android