blob: 6b404124476594b11f0aafc97251b7f90fbef934 [file] [log] [blame]
The Android Open Source Project89fa4ad2009-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
27#include <utils/IServiceManager.h>
28#include <utils/IPCThreadState.h>
29
30#include <media/mediaplayer.h>
31#include <media/AudioTrack.h>
32
33#include <utils/MemoryBase.h>
34
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;
94}
95
96void MediaPlayer::onFirstRef()
97{
98 addObitRecipient(this);
99}
100
101MediaPlayer::~MediaPlayer()
102{
103 LOGV("destructor");
104 removeObitRecipient(this);
105 disconnect();
106 IPCThreadState::self()->flushCommands();
107}
108
109void MediaPlayer::disconnect()
110{
111 LOGV("disconnect");
112 sp<IMediaPlayer> p;
113 {
114 Mutex::Autolock _l(mLock);
115 p = mPlayer;
116 mPlayer.clear();
117 }
118
119 if (p != 0) {
120 p->disconnect();
121 }
122}
123
124// always call with lock held
125void MediaPlayer::clear_l()
126{
127 mDuration = -1;
128 mCurrentPosition = -1;
129 mSeekPosition = -1;
130 mVideoWidth = mVideoHeight = 0;
131}
132
133status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
134{
135 LOGV("setListener");
136 Mutex::Autolock _l(mLock);
137 mListener = listener;
138 return NO_ERROR;
139}
140
141
142status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
143{
144 status_t err = UNKNOWN_ERROR;
145 sp<IMediaPlayer> p;
146 { // scope for the lock
147 Mutex::Autolock _l(mLock);
148
149 if ( !( mCurrentState & ( MEDIA_PLAYER_IDLE | MEDIA_PLAYER_STATE_ERROR ) ) ) {
150 LOGE("setDataSource called in state %d", mCurrentState);
151 return INVALID_OPERATION;
152 }
153
154 clear_l();
155 p = mPlayer;
156 mPlayer = player;
157 if (player != 0) {
158 mCurrentState = MEDIA_PLAYER_INITIALIZED;
159 err = NO_ERROR;
160 } else {
161 LOGE("Unable to to create media player");
162 }
163 }
164
165 if (p != 0) {
166 p->disconnect();
167 }
168
169 return err;
170}
171
172status_t MediaPlayer::setDataSource(const char *url)
173{
174 LOGV("setDataSource(%s)", url);
175 status_t err = BAD_VALUE;
176 if (url != NULL) {
177 const sp<IMediaPlayerService>& service(getMediaPlayerService());
178 if (service != 0) {
179 sp<IMediaPlayer> player(service->create(getpid(), this, url));
180 err = setDataSource(player);
181 }
182 }
183 return err;
184}
185
186status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
187{
188 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
189 status_t err = UNKNOWN_ERROR;
190 const sp<IMediaPlayerService>& service(getMediaPlayerService());
191 if (service != 0) {
192 sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
193 err = setDataSource(player);
194 }
195 return err;
196}
197
198status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
199{
200 LOGV("setVideoSurface");
201 Mutex::Autolock _l(mLock);
202 if (mPlayer == 0) return NO_INIT;
203 return mPlayer->setVideoSurface(surface->getISurface());
204}
205
206// must call with lock held
207status_t MediaPlayer::prepareAsync_l()
208{
209 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
210 mPlayer->setAudioStreamType(mStreamType);
211 mCurrentState = MEDIA_PLAYER_PREPARING;
212 return mPlayer->prepareAsync();
213 }
214 LOGE("prepareAsync called in state %d", mCurrentState);
215 return INVALID_OPERATION;
216}
217
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700218// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
219// one defined in the Android framework and one provided by the implementation
220// that generated the error. The sync version of prepare returns only 1 error
221// code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800222status_t MediaPlayer::prepare()
223{
224 LOGV("prepare");
225 Mutex::Autolock _l(mLock);
226 if (mPrepareSync) return -EALREADY;
227 mPrepareSync = true;
228 status_t ret = prepareAsync_l();
229 if (ret != NO_ERROR) return ret;
230
231 if (mPrepareSync) {
232 mSignal.wait(mLock); // wait for prepare done
233 mPrepareSync = false;
234 }
235 LOGV("prepare complete - status=%d", mPrepareStatus);
236 return mPrepareStatus;
237}
238
239status_t MediaPlayer::prepareAsync()
240{
241 LOGV("prepareAsync");
242 Mutex::Autolock _l(mLock);
243 return prepareAsync_l();
244}
245
246status_t MediaPlayer::start()
247{
248 LOGV("start");
249 Mutex::Autolock _l(mLock);
250 if (mCurrentState & MEDIA_PLAYER_STARTED)
251 return NO_ERROR;
252 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
253 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
254 mPlayer->setLooping(mLoop);
255 mPlayer->setVolume(mLeftVolume, mRightVolume);
256 mCurrentState = MEDIA_PLAYER_STARTED;
257 status_t ret = mPlayer->start();
258 if (ret != NO_ERROR) {
259 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
260 } else {
261 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
262 LOGV("playback completed immediately following start()");
263 }
264 }
265 return ret;
266 }
267 LOGE("start called in state %d", mCurrentState);
268 return INVALID_OPERATION;
269}
270
271status_t MediaPlayer::stop()
272{
273 LOGV("stop");
274 Mutex::Autolock _l(mLock);
275 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
276 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
277 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
278 status_t ret = mPlayer->stop();
279 if (ret != NO_ERROR) {
280 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
281 } else {
282 mCurrentState = MEDIA_PLAYER_STOPPED;
283 }
284 return ret;
285 }
286 LOGE("stop called in state %d", mCurrentState);
287 return INVALID_OPERATION;
288}
289
290status_t MediaPlayer::pause()
291{
292 LOGV("pause");
293 Mutex::Autolock _l(mLock);
294 if (mCurrentState & MEDIA_PLAYER_PAUSED)
295 return NO_ERROR;
296 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
297 status_t ret = mPlayer->pause();
298 if (ret != NO_ERROR) {
299 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
300 } else {
301 mCurrentState = MEDIA_PLAYER_PAUSED;
302 }
303 return ret;
304 }
305 LOGE("pause called in state %d", mCurrentState);
306 return INVALID_OPERATION;
307}
308
309bool MediaPlayer::isPlaying()
310{
311 Mutex::Autolock _l(mLock);
312 if (mPlayer != 0) {
313 bool temp = false;
314 mPlayer->isPlaying(&temp);
315 LOGV("isPlaying: %d", temp);
316 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
317 LOGE("internal/external state mismatch corrected");
318 mCurrentState = MEDIA_PLAYER_PAUSED;
319 }
320 return temp;
321 }
322 LOGV("isPlaying: no active player");
323 return false;
324}
325
326status_t MediaPlayer::getVideoWidth(int *w)
327{
328 LOGV("getVideoWidth");
329 Mutex::Autolock _l(mLock);
330 if (mPlayer == 0) return INVALID_OPERATION;
331 *w = mVideoWidth;
332 return NO_ERROR;
333}
334
335status_t MediaPlayer::getVideoHeight(int *h)
336{
337 LOGV("getVideoHeight");
338 Mutex::Autolock _l(mLock);
339 if (mPlayer == 0) return INVALID_OPERATION;
340 *h = mVideoHeight;
341 return NO_ERROR;
342}
343
344status_t MediaPlayer::getCurrentPosition(int *msec)
345{
346 LOGV("getCurrentPosition");
347 Mutex::Autolock _l(mLock);
348 if (mPlayer != 0) {
349 if (mCurrentPosition >= 0) {
350 LOGV("Using cached seek position: %d", mCurrentPosition);
351 *msec = mCurrentPosition;
352 return NO_ERROR;
353 }
354 return mPlayer->getCurrentPosition(msec);
355 }
356 return INVALID_OPERATION;
357}
358
359status_t MediaPlayer::getDuration_l(int *msec)
360{
361 LOGV("getDuration");
362 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
363 if (mPlayer != 0 && isValidState) {
364 status_t ret = NO_ERROR;
365 if (mDuration <= 0)
366 ret = mPlayer->getDuration(&mDuration);
367 if (msec)
368 *msec = mDuration;
369 return ret;
370 }
371 LOGE("Attempt to call getDuration without a valid mediaplayer");
372 return INVALID_OPERATION;
373}
374
375status_t MediaPlayer::getDuration(int *msec)
376{
377 Mutex::Autolock _l(mLock);
378 return getDuration_l(msec);
379}
380
381status_t MediaPlayer::seekTo_l(int msec)
382{
383 LOGV("seekTo %d", msec);
384 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
385 if ( msec < 0 ) {
386 LOGW("Attempt to seek to invalid position: %d", msec);
387 msec = 0;
388 } else if ((mDuration > 0) && (msec > mDuration)) {
389 LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
390 msec = mDuration;
391 }
392 // cache duration
393 mCurrentPosition = msec;
394 if (mSeekPosition < 0) {
395 getDuration_l(NULL);
396 mSeekPosition = msec;
397 return mPlayer->seekTo(msec);
398 }
399 else {
400 LOGV("Seek in progress - queue up seekTo[%d]", msec);
401 return NO_ERROR;
402 }
403 }
404 LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
405 return INVALID_OPERATION;
406}
407
408status_t MediaPlayer::seekTo(int msec)
409{
410 Mutex::Autolock _l(mLock);
411 return seekTo_l(msec);
412}
413
414status_t MediaPlayer::reset()
415{
416 LOGV("reset");
417 Mutex::Autolock _l(mLock);
418 mLoop = false;
419 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
420 mPrepareSync = false;
421 if (mPlayer != 0) {
422 status_t ret = mPlayer->reset();
423 if (ret != NO_ERROR) {
424 LOGE("reset() failed with return code (%d)", ret);
425 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
426 } else {
427 mCurrentState = MEDIA_PLAYER_IDLE;
428 }
429 return ret;
430 }
431 clear_l();
432 return NO_ERROR;
433}
434
435status_t MediaPlayer::setAudioStreamType(int type)
436{
437 LOGV("MediaPlayer::setAudioStreamType");
438 Mutex::Autolock _l(mLock);
439 if (mStreamType == type) return NO_ERROR;
440 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
441 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
442 // Can't change the stream type after prepare
443 LOGE("setAudioStream called in state %d", mCurrentState);
444 return INVALID_OPERATION;
445 }
446 // cache
447 mStreamType = type;
448 return OK;
449}
450
451status_t MediaPlayer::setLooping(int loop)
452{
453 LOGV("MediaPlayer::setLooping");
454 Mutex::Autolock _l(mLock);
455 mLoop = (loop != 0);
456 if (mPlayer != 0) {
457 return mPlayer->setLooping(loop);
458 }
459 return OK;
460}
461
462bool MediaPlayer::isLooping() {
463 LOGV("isLooping");
464 Mutex::Autolock _l(mLock);
465 if (mPlayer != 0) {
466 return mLoop;
467 }
468 LOGV("isLooping: no active player");
469 return false;
470}
471
472status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
473{
474 LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
475 Mutex::Autolock _l(mLock);
476 mLeftVolume = leftVolume;
477 mRightVolume = rightVolume;
478 if (mPlayer != 0) {
479 return mPlayer->setVolume(leftVolume, rightVolume);
480 }
481 return OK;
482}
483
484void MediaPlayer::notify(int msg, int ext1, int ext2)
485{
486 LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
487 bool send = true;
488
489 // TODO: In the future, we might be on the same thread if the app is
490 // running in the same process as the media server. In that case,
491 // this will deadlock.
492 mLock.lock();
493 if (mPlayer == 0) {
494 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
495 mLock.unlock(); // release the lock when done.
496 return;
497 }
498
499 switch (msg) {
500 case MEDIA_NOP: // interface test message
501 break;
502 case MEDIA_PREPARED:
503 LOGV("prepared");
504 mCurrentState = MEDIA_PLAYER_PREPARED;
505 if (mPrepareSync) {
506 LOGV("signal application thread");
507 mPrepareSync = false;
508 mPrepareStatus = NO_ERROR;
509 mSignal.signal();
510 }
511 break;
512 case MEDIA_PLAYBACK_COMPLETE:
513 LOGV("playback complete");
514 if (!mLoop) {
515 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
516 }
517 break;
518 case MEDIA_ERROR:
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700519 // Always log errors.
520 // ext1: Media framework error code.
521 // ext2: Implementation dependant error code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800522 LOGE("error (%d, %d)", ext1, ext2);
523 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
524 if (mPrepareSync)
525 {
526 LOGV("signal application thread");
527 mPrepareSync = false;
528 mPrepareStatus = ext1;
529 mSignal.signal();
530 send = false;
531 }
532 break;
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700533 case MEDIA_INFO:
534 // ext1: Media framework error code.
535 // ext2: Implementation dependant error code.
536 LOGW("info/warning (%d, %d)", ext1, ext2);
537 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800538 case MEDIA_SEEK_COMPLETE:
539 LOGV("Received seek complete");
540 if (mSeekPosition != mCurrentPosition) {
541 LOGV("Executing queued seekTo(%d)", mSeekPosition);
542 mSeekPosition = -1;
543 seekTo_l(mCurrentPosition);
544 }
545 else {
546 LOGV("All seeks complete - return to regularly scheduled program");
547 mCurrentPosition = mSeekPosition = -1;
548 }
549 break;
550 case MEDIA_BUFFERING_UPDATE:
551 LOGV("buffering %d", ext1);
552 break;
553 case MEDIA_SET_VIDEO_SIZE:
554 LOGV("New video size %d x %d", ext1, ext2);
555 mVideoWidth = ext1;
556 mVideoHeight = ext2;
557 break;
558 default:
559 LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
560 break;
561 }
562
563 sp<MediaPlayerListener> listener = mListener;
564 mLock.unlock();
565
566 // this prevents re-entrant calls into client code
567 if ((listener != 0) && send) {
568 Mutex::Autolock _l(mNotifyLock);
569 LOGV("callback application");
570 listener->notify(msg, ext1, ext2);
571 LOGV("back from callback");
572 }
573}
574
575void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) {
576 LOGW("MediaPlayer server died!");
577
578 // Need to do this with the lock held
579 SortedVector< wp<MediaPlayer> > list;
580 {
581 Mutex::Autolock _l(MediaPlayer::sServiceLock);
582 MediaPlayer::sMediaPlayerService.clear();
583 list = sObitRecipients;
584 }
585
586 // Notify application when media server dies.
587 // Don't hold the static lock during callback in case app
588 // makes a call that needs the lock.
589 size_t count = list.size();
590 for (size_t iter = 0; iter < count; ++iter) {
591 sp<MediaPlayer> player = list[iter].promote();
592 if ((player != 0) && (player->mPlayer != 0)) {
593 player->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
594 }
595 }
596}
597
598MediaPlayer::DeathNotifier::~DeathNotifier()
599{
600 Mutex::Autolock _l(sServiceLock);
601 sObitRecipients.clear();
602 if (sMediaPlayerService != 0) {
603 sMediaPlayerService->asBinder()->unlinkToDeath(this);
604 }
605}
606
607/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
608{
609 LOGV("decode(%s)", url);
610 sp<IMemory> p;
611 const sp<IMediaPlayerService>& service = getMediaPlayerService();
612 if (service != 0) {
613 p = sMediaPlayerService->decode(url, pSampleRate, pNumChannels, pFormat);
614 } else {
615 LOGE("Unable to locate media service");
616 }
617 return p;
618
619}
620
621/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
622{
623 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
624 sp<IMemory> p;
625 const sp<IMediaPlayerService>& service = getMediaPlayerService();
626 if (service != 0) {
627 p = sMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
628 } else {
629 LOGE("Unable to locate media service");
630 }
631 return p;
632
633}
634
635}; // namespace android