blob: d8c622f3781f428d185f31932ae96070dc94fef7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* mediaplayer.cpp
2**
3** Copyright 2006, 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//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaPlayer"
20#include <utils/Log.h>
21
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <fcntl.h>
26
Mathias Agopian07952722009-05-19 19:08:10 -070027#include <binder/IServiceManager.h>
28#include <binder/IPCThreadState.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
30#include <media/mediaplayer.h>
31#include <media/AudioTrack.h>
32
Mathias Agopian07952722009-05-19 19:08:10 -070033#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
35namespace android {
36
37// client singleton for binder interface to service
38Mutex MediaPlayer::sServiceLock;
39sp<IMediaPlayerService> MediaPlayer::sMediaPlayerService;
40sp<MediaPlayer::DeathNotifier> MediaPlayer::sDeathNotifier;
41SortedVector< wp<MediaPlayer> > MediaPlayer::sObitRecipients;
42
43// establish binder interface to service
44const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
45{
46 Mutex::Autolock _l(sServiceLock);
47 if (sMediaPlayerService.get() == 0) {
48 sp<IServiceManager> sm = defaultServiceManager();
49 sp<IBinder> binder;
50 do {
51 binder = sm->getService(String16("media.player"));
52 if (binder != 0)
53 break;
54 LOGW("MediaPlayerService not published, waiting...");
55 usleep(500000); // 0.5 s
56 } while(true);
57 if (sDeathNotifier == NULL) {
58 sDeathNotifier = new DeathNotifier();
59 }
60 binder->linkToDeath(sDeathNotifier);
61 sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
62 }
63 LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
64 return sMediaPlayerService;
65}
66
67void MediaPlayer::addObitRecipient(const wp<MediaPlayer>& recipient)
68{
69 Mutex::Autolock _l(sServiceLock);
70 sObitRecipients.add(recipient);
71}
72
73void MediaPlayer::removeObitRecipient(const wp<MediaPlayer>& recipient)
74{
75 Mutex::Autolock _l(sServiceLock);
76 sObitRecipients.remove(recipient);
77}
78
79MediaPlayer::MediaPlayer()
80{
81 LOGV("constructor");
82 mListener = NULL;
83 mCookie = NULL;
84 mDuration = -1;
85 mStreamType = AudioSystem::MUSIC;
86 mCurrentPosition = -1;
87 mSeekPosition = -1;
88 mCurrentState = MEDIA_PLAYER_IDLE;
89 mPrepareSync = false;
90 mPrepareStatus = NO_ERROR;
91 mLoop = false;
92 mLeftVolume = mRightVolume = 1.0;
93 mVideoWidth = mVideoHeight = 0;
Jason Samsebb020a2009-03-24 18:45:22 -070094 mLockThreadId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095}
96
97void MediaPlayer::onFirstRef()
98{
99 addObitRecipient(this);
100}
101
102MediaPlayer::~MediaPlayer()
103{
104 LOGV("destructor");
105 removeObitRecipient(this);
106 disconnect();
107 IPCThreadState::self()->flushCommands();
108}
109
110void MediaPlayer::disconnect()
111{
112 LOGV("disconnect");
113 sp<IMediaPlayer> p;
114 {
115 Mutex::Autolock _l(mLock);
116 p = mPlayer;
117 mPlayer.clear();
118 }
119
120 if (p != 0) {
121 p->disconnect();
122 }
123}
124
125// always call with lock held
126void MediaPlayer::clear_l()
127{
128 mDuration = -1;
129 mCurrentPosition = -1;
130 mSeekPosition = -1;
131 mVideoWidth = mVideoHeight = 0;
132}
133
134status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
135{
136 LOGV("setListener");
137 Mutex::Autolock _l(mLock);
138 mListener = listener;
139 return NO_ERROR;
140}
141
142
143status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
144{
145 status_t err = UNKNOWN_ERROR;
146 sp<IMediaPlayer> p;
147 { // scope for the lock
148 Mutex::Autolock _l(mLock);
149
150 if ( !( mCurrentState & ( MEDIA_PLAYER_IDLE | MEDIA_PLAYER_STATE_ERROR ) ) ) {
151 LOGE("setDataSource called in state %d", mCurrentState);
152 return INVALID_OPERATION;
153 }
154
155 clear_l();
156 p = mPlayer;
157 mPlayer = player;
158 if (player != 0) {
159 mCurrentState = MEDIA_PLAYER_INITIALIZED;
160 err = NO_ERROR;
161 } else {
162 LOGE("Unable to to create media player");
163 }
164 }
165
166 if (p != 0) {
167 p->disconnect();
168 }
169
170 return err;
171}
172
173status_t MediaPlayer::setDataSource(const char *url)
174{
175 LOGV("setDataSource(%s)", url);
176 status_t err = BAD_VALUE;
177 if (url != NULL) {
178 const sp<IMediaPlayerService>& service(getMediaPlayerService());
179 if (service != 0) {
180 sp<IMediaPlayer> player(service->create(getpid(), this, url));
181 err = setDataSource(player);
182 }
183 }
184 return err;
185}
186
187status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
188{
189 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
190 status_t err = UNKNOWN_ERROR;
191 const sp<IMediaPlayerService>& service(getMediaPlayerService());
192 if (service != 0) {
193 sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
194 err = setDataSource(player);
195 }
196 return err;
197}
198
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700199status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
200{
201 Mutex::Autolock _l(mLock);
202 if ((mPlayer != NULL) && ( mCurrentState & MEDIA_PLAYER_INITIALIZED ))
203 {
204 LOGV("invoke %d", request.dataSize());
205 return mPlayer->invoke(request, reply);
206 }
207 LOGE("invoke failed: wrong state %X", mCurrentState);
208 return INVALID_OPERATION;
209}
210
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700211status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
212{
213 LOGD("setMetadataFilter");
214 Mutex::Autolock _l(mLock);
215 if (mPlayer == NULL)
216 {
217 return NO_INIT;
218 }
219 return mPlayer->setMetadataFilter(filter);
220}
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
223{
224 LOGV("setVideoSurface");
225 Mutex::Autolock _l(mLock);
226 if (mPlayer == 0) return NO_INIT;
227 return mPlayer->setVideoSurface(surface->getISurface());
228}
229
230// must call with lock held
231status_t MediaPlayer::prepareAsync_l()
232{
233 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
234 mPlayer->setAudioStreamType(mStreamType);
235 mCurrentState = MEDIA_PLAYER_PREPARING;
236 return mPlayer->prepareAsync();
237 }
238 LOGE("prepareAsync called in state %d", mCurrentState);
239 return INVALID_OPERATION;
240}
241
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700242// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
243// one defined in the Android framework and one provided by the implementation
244// that generated the error. The sync version of prepare returns only 1 error
245// code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246status_t MediaPlayer::prepare()
247{
248 LOGV("prepare");
249 Mutex::Autolock _l(mLock);
Jason Samsebb020a2009-03-24 18:45:22 -0700250 mLockThreadId = getThreadId();
251 if (mPrepareSync) {
252 mLockThreadId = 0;
253 return -EALREADY;
254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 mPrepareSync = true;
256 status_t ret = prepareAsync_l();
Jason Samsebb020a2009-03-24 18:45:22 -0700257 if (ret != NO_ERROR) {
258 mLockThreadId = 0;
259 return ret;
260 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261
262 if (mPrepareSync) {
263 mSignal.wait(mLock); // wait for prepare done
264 mPrepareSync = false;
265 }
266 LOGV("prepare complete - status=%d", mPrepareStatus);
Jason Samsebb020a2009-03-24 18:45:22 -0700267 mLockThreadId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 return mPrepareStatus;
269}
270
271status_t MediaPlayer::prepareAsync()
272{
273 LOGV("prepareAsync");
274 Mutex::Autolock _l(mLock);
275 return prepareAsync_l();
276}
277
278status_t MediaPlayer::start()
279{
280 LOGV("start");
281 Mutex::Autolock _l(mLock);
282 if (mCurrentState & MEDIA_PLAYER_STARTED)
283 return NO_ERROR;
284 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
285 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
286 mPlayer->setLooping(mLoop);
287 mPlayer->setVolume(mLeftVolume, mRightVolume);
288 mCurrentState = MEDIA_PLAYER_STARTED;
289 status_t ret = mPlayer->start();
290 if (ret != NO_ERROR) {
291 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
292 } else {
293 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
294 LOGV("playback completed immediately following start()");
295 }
296 }
297 return ret;
298 }
299 LOGE("start called in state %d", mCurrentState);
300 return INVALID_OPERATION;
301}
302
303status_t MediaPlayer::stop()
304{
305 LOGV("stop");
306 Mutex::Autolock _l(mLock);
307 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
308 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
309 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
310 status_t ret = mPlayer->stop();
311 if (ret != NO_ERROR) {
312 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
313 } else {
314 mCurrentState = MEDIA_PLAYER_STOPPED;
315 }
316 return ret;
317 }
318 LOGE("stop called in state %d", mCurrentState);
319 return INVALID_OPERATION;
320}
321
322status_t MediaPlayer::pause()
323{
324 LOGV("pause");
325 Mutex::Autolock _l(mLock);
326 if (mCurrentState & MEDIA_PLAYER_PAUSED)
327 return NO_ERROR;
328 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
329 status_t ret = mPlayer->pause();
330 if (ret != NO_ERROR) {
331 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
332 } else {
333 mCurrentState = MEDIA_PLAYER_PAUSED;
334 }
335 return ret;
336 }
337 LOGE("pause called in state %d", mCurrentState);
338 return INVALID_OPERATION;
339}
340
341bool MediaPlayer::isPlaying()
342{
343 Mutex::Autolock _l(mLock);
344 if (mPlayer != 0) {
345 bool temp = false;
346 mPlayer->isPlaying(&temp);
347 LOGV("isPlaying: %d", temp);
348 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
349 LOGE("internal/external state mismatch corrected");
350 mCurrentState = MEDIA_PLAYER_PAUSED;
351 }
352 return temp;
353 }
354 LOGV("isPlaying: no active player");
355 return false;
356}
357
358status_t MediaPlayer::getVideoWidth(int *w)
359{
360 LOGV("getVideoWidth");
361 Mutex::Autolock _l(mLock);
362 if (mPlayer == 0) return INVALID_OPERATION;
363 *w = mVideoWidth;
364 return NO_ERROR;
365}
366
367status_t MediaPlayer::getVideoHeight(int *h)
368{
369 LOGV("getVideoHeight");
370 Mutex::Autolock _l(mLock);
371 if (mPlayer == 0) return INVALID_OPERATION;
372 *h = mVideoHeight;
373 return NO_ERROR;
374}
375
376status_t MediaPlayer::getCurrentPosition(int *msec)
377{
378 LOGV("getCurrentPosition");
379 Mutex::Autolock _l(mLock);
380 if (mPlayer != 0) {
381 if (mCurrentPosition >= 0) {
382 LOGV("Using cached seek position: %d", mCurrentPosition);
383 *msec = mCurrentPosition;
384 return NO_ERROR;
385 }
386 return mPlayer->getCurrentPosition(msec);
387 }
388 return INVALID_OPERATION;
389}
390
391status_t MediaPlayer::getDuration_l(int *msec)
392{
393 LOGV("getDuration");
394 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
395 if (mPlayer != 0 && isValidState) {
396 status_t ret = NO_ERROR;
397 if (mDuration <= 0)
398 ret = mPlayer->getDuration(&mDuration);
399 if (msec)
400 *msec = mDuration;
401 return ret;
402 }
403 LOGE("Attempt to call getDuration without a valid mediaplayer");
404 return INVALID_OPERATION;
405}
406
407status_t MediaPlayer::getDuration(int *msec)
408{
409 Mutex::Autolock _l(mLock);
410 return getDuration_l(msec);
411}
412
413status_t MediaPlayer::seekTo_l(int msec)
414{
415 LOGV("seekTo %d", msec);
416 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
417 if ( msec < 0 ) {
418 LOGW("Attempt to seek to invalid position: %d", msec);
419 msec = 0;
420 } else if ((mDuration > 0) && (msec > mDuration)) {
421 LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
422 msec = mDuration;
423 }
424 // cache duration
425 mCurrentPosition = msec;
426 if (mSeekPosition < 0) {
427 getDuration_l(NULL);
428 mSeekPosition = msec;
429 return mPlayer->seekTo(msec);
430 }
431 else {
432 LOGV("Seek in progress - queue up seekTo[%d]", msec);
433 return NO_ERROR;
434 }
435 }
436 LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
437 return INVALID_OPERATION;
438}
439
440status_t MediaPlayer::seekTo(int msec)
441{
Andreas Hubereffd8d52009-03-24 20:48:51 -0700442 mLockThreadId = getThreadId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 Mutex::Autolock _l(mLock);
Andreas Hubereffd8d52009-03-24 20:48:51 -0700444 status_t result = seekTo_l(msec);
445 mLockThreadId = 0;
446
447 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448}
449
450status_t MediaPlayer::reset()
451{
452 LOGV("reset");
453 Mutex::Autolock _l(mLock);
454 mLoop = false;
455 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
456 mPrepareSync = false;
457 if (mPlayer != 0) {
458 status_t ret = mPlayer->reset();
459 if (ret != NO_ERROR) {
460 LOGE("reset() failed with return code (%d)", ret);
461 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
462 } else {
463 mCurrentState = MEDIA_PLAYER_IDLE;
464 }
465 return ret;
466 }
467 clear_l();
468 return NO_ERROR;
469}
470
471status_t MediaPlayer::setAudioStreamType(int type)
472{
473 LOGV("MediaPlayer::setAudioStreamType");
474 Mutex::Autolock _l(mLock);
475 if (mStreamType == type) return NO_ERROR;
476 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
477 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
478 // Can't change the stream type after prepare
479 LOGE("setAudioStream called in state %d", mCurrentState);
480 return INVALID_OPERATION;
481 }
482 // cache
483 mStreamType = type;
484 return OK;
485}
486
487status_t MediaPlayer::setLooping(int loop)
488{
489 LOGV("MediaPlayer::setLooping");
490 Mutex::Autolock _l(mLock);
491 mLoop = (loop != 0);
492 if (mPlayer != 0) {
493 return mPlayer->setLooping(loop);
494 }
495 return OK;
496}
497
498bool MediaPlayer::isLooping() {
499 LOGV("isLooping");
500 Mutex::Autolock _l(mLock);
501 if (mPlayer != 0) {
502 return mLoop;
503 }
504 LOGV("isLooping: no active player");
505 return false;
506}
507
508status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
509{
510 LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
511 Mutex::Autolock _l(mLock);
512 mLeftVolume = leftVolume;
513 mRightVolume = rightVolume;
514 if (mPlayer != 0) {
515 return mPlayer->setVolume(leftVolume, rightVolume);
516 }
517 return OK;
518}
519
520void MediaPlayer::notify(int msg, int ext1, int ext2)
521{
522 LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
523 bool send = true;
Jason Samsebb020a2009-03-24 18:45:22 -0700524 bool locked = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525
526 // TODO: In the future, we might be on the same thread if the app is
527 // running in the same process as the media server. In that case,
528 // this will deadlock.
Nicolas Catania32f82772009-06-11 16:33:49 -0700529 //
Jason Samsebb020a2009-03-24 18:45:22 -0700530 // The threadId hack below works around this for the care of prepare
Andreas Hubereffd8d52009-03-24 20:48:51 -0700531 // and seekTo within the same process.
532 // FIXME: Remember, this is a hack, it's not even a hack that is applied
533 // consistently for all use-cases, this needs to be revisited.
Jason Samsebb020a2009-03-24 18:45:22 -0700534 if (mLockThreadId != getThreadId()) {
535 mLock.lock();
536 locked = true;
Nicolas Catania32f82772009-06-11 16:33:49 -0700537 }
Jason Samsebb020a2009-03-24 18:45:22 -0700538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 if (mPlayer == 0) {
540 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Samsebb020a2009-03-24 18:45:22 -0700541 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 return;
543 }
544
545 switch (msg) {
546 case MEDIA_NOP: // interface test message
547 break;
548 case MEDIA_PREPARED:
549 LOGV("prepared");
550 mCurrentState = MEDIA_PLAYER_PREPARED;
551 if (mPrepareSync) {
552 LOGV("signal application thread");
553 mPrepareSync = false;
554 mPrepareStatus = NO_ERROR;
555 mSignal.signal();
556 }
557 break;
558 case MEDIA_PLAYBACK_COMPLETE:
559 LOGV("playback complete");
560 if (!mLoop) {
561 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
562 }
563 break;
564 case MEDIA_ERROR:
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700565 // Always log errors.
566 // ext1: Media framework error code.
567 // ext2: Implementation dependant error code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 LOGE("error (%d, %d)", ext1, ext2);
569 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
570 if (mPrepareSync)
571 {
572 LOGV("signal application thread");
573 mPrepareSync = false;
574 mPrepareStatus = ext1;
575 mSignal.signal();
576 send = false;
577 }
578 break;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700579 case MEDIA_INFO:
580 // ext1: Media framework error code.
581 // ext2: Implementation dependant error code.
582 LOGW("info/warning (%d, %d)", ext1, ext2);
583 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 case MEDIA_SEEK_COMPLETE:
585 LOGV("Received seek complete");
586 if (mSeekPosition != mCurrentPosition) {
587 LOGV("Executing queued seekTo(%d)", mSeekPosition);
588 mSeekPosition = -1;
589 seekTo_l(mCurrentPosition);
590 }
591 else {
592 LOGV("All seeks complete - return to regularly scheduled program");
593 mCurrentPosition = mSeekPosition = -1;
594 }
595 break;
596 case MEDIA_BUFFERING_UPDATE:
597 LOGV("buffering %d", ext1);
598 break;
599 case MEDIA_SET_VIDEO_SIZE:
600 LOGV("New video size %d x %d", ext1, ext2);
601 mVideoWidth = ext1;
602 mVideoHeight = ext2;
603 break;
604 default:
605 LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
606 break;
607 }
608
609 sp<MediaPlayerListener> listener = mListener;
Jason Samsebb020a2009-03-24 18:45:22 -0700610 if (locked) mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611
612 // this prevents re-entrant calls into client code
613 if ((listener != 0) && send) {
614 Mutex::Autolock _l(mNotifyLock);
615 LOGV("callback application");
616 listener->notify(msg, ext1, ext2);
617 LOGV("back from callback");
618 }
619}
620
621void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) {
622 LOGW("MediaPlayer server died!");
623
624 // Need to do this with the lock held
625 SortedVector< wp<MediaPlayer> > list;
626 {
627 Mutex::Autolock _l(MediaPlayer::sServiceLock);
628 MediaPlayer::sMediaPlayerService.clear();
629 list = sObitRecipients;
630 }
631
632 // Notify application when media server dies.
633 // Don't hold the static lock during callback in case app
634 // makes a call that needs the lock.
635 size_t count = list.size();
636 for (size_t iter = 0; iter < count; ++iter) {
637 sp<MediaPlayer> player = list[iter].promote();
638 if ((player != 0) && (player->mPlayer != 0)) {
639 player->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
640 }
641 }
642}
643
644MediaPlayer::DeathNotifier::~DeathNotifier()
645{
646 Mutex::Autolock _l(sServiceLock);
647 sObitRecipients.clear();
648 if (sMediaPlayerService != 0) {
649 sMediaPlayerService->asBinder()->unlinkToDeath(this);
650 }
651}
652
653/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
654{
655 LOGV("decode(%s)", url);
656 sp<IMemory> p;
657 const sp<IMediaPlayerService>& service = getMediaPlayerService();
658 if (service != 0) {
659 p = sMediaPlayerService->decode(url, pSampleRate, pNumChannels, pFormat);
660 } else {
661 LOGE("Unable to locate media service");
662 }
663 return p;
664
665}
666
667/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
668{
669 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
670 sp<IMemory> p;
671 const sp<IMediaPlayerService>& service = getMediaPlayerService();
672 if (service != 0) {
673 p = sMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
674 } else {
675 LOGE("Unable to locate media service");
676 }
677 return p;
678
679}
680
681}; // namespace android