blob: 178039c6e03baa6cab2d5146b302b2ba9d1c7dba [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
Mathias Agopian75624082009-05-19 19:08:10 -070027#include <binder/IServiceManager.h>
28#include <binder/IPCThreadState.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080029
Jamie Gennis61c7ef52011-07-13 12:59:34 -070030#include <gui/SurfaceTextureClient.h>
31
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080032#include <media/mediaplayer.h>
33#include <media/AudioTrack.h>
34
Mathias Agopian3cf61352010-02-09 17:46:37 -080035#include <surfaceflinger/Surface.h>
36
Mathias Agopian75624082009-05-19 19:08:10 -070037#include <binder/MemoryBase.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080038
Andreas Huber2db84552010-01-28 11:19:57 -080039#include <utils/KeyedVector.h>
40#include <utils/String8.h>
41
Dima Zavin64760242011-05-11 14:15:23 -070042#include <system/audio.h>
Jamie Gennis61c7ef52011-07-13 12:59:34 -070043#include <system/window.h>
Dima Zavinfce7a472011-04-19 22:30:36 -070044
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080045namespace android {
46
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080047MediaPlayer::MediaPlayer()
48{
49 LOGV("constructor");
50 mListener = NULL;
51 mCookie = NULL;
52 mDuration = -1;
Dima Zavinfce7a472011-04-19 22:30:36 -070053 mStreamType = AUDIO_STREAM_MUSIC;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080054 mCurrentPosition = -1;
55 mSeekPosition = -1;
56 mCurrentState = MEDIA_PLAYER_IDLE;
57 mPrepareSync = false;
58 mPrepareStatus = NO_ERROR;
59 mLoop = false;
60 mLeftVolume = mRightVolume = 1.0;
61 mVideoWidth = mVideoHeight = 0;
Jason Sams1af452f2009-03-24 18:45:22 -070062 mLockThreadId = 0;
Eric Laurenta514bdb2010-06-21 09:27:30 -070063 mAudioSessionId = AudioSystem::newAudioSessionId();
Eric Laurent8c563ed2010-10-07 18:23:03 -070064 mSendLevel = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080065}
66
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080067MediaPlayer::~MediaPlayer()
68{
69 LOGV("destructor");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080070 disconnect();
71 IPCThreadState::self()->flushCommands();
72}
73
74void MediaPlayer::disconnect()
75{
76 LOGV("disconnect");
77 sp<IMediaPlayer> p;
78 {
79 Mutex::Autolock _l(mLock);
80 p = mPlayer;
81 mPlayer.clear();
82 }
83
84 if (p != 0) {
85 p->disconnect();
86 }
87}
88
89// always call with lock held
90void MediaPlayer::clear_l()
91{
92 mDuration = -1;
93 mCurrentPosition = -1;
94 mSeekPosition = -1;
95 mVideoWidth = mVideoHeight = 0;
96}
97
98status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
99{
100 LOGV("setListener");
101 Mutex::Autolock _l(mLock);
102 mListener = listener;
103 return NO_ERROR;
104}
105
106
107status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
108{
109 status_t err = UNKNOWN_ERROR;
110 sp<IMediaPlayer> p;
111 { // scope for the lock
112 Mutex::Autolock _l(mLock);
113
Marco Nelissen83ff1432010-03-10 10:53:16 -0800114 if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
115 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800116 LOGE("setDataSource called in state %d", mCurrentState);
117 return INVALID_OPERATION;
118 }
119
120 clear_l();
121 p = mPlayer;
122 mPlayer = player;
123 if (player != 0) {
124 mCurrentState = MEDIA_PLAYER_INITIALIZED;
125 err = NO_ERROR;
126 } else {
127 LOGE("Unable to to create media player");
128 }
129 }
130
131 if (p != 0) {
132 p->disconnect();
133 }
134
135 return err;
136}
137
Andreas Huber2db84552010-01-28 11:19:57 -0800138status_t MediaPlayer::setDataSource(
139 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800140{
141 LOGV("setDataSource(%s)", url);
142 status_t err = BAD_VALUE;
143 if (url != NULL) {
144 const sp<IMediaPlayerService>& service(getMediaPlayerService());
145 if (service != 0) {
Andreas Huber2db84552010-01-28 11:19:57 -0800146 sp<IMediaPlayer> player(
Eric Laurenta514bdb2010-06-21 09:27:30 -0700147 service->create(getpid(), this, url, headers, mAudioSessionId));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800148 err = setDataSource(player);
149 }
150 }
151 return err;
152}
153
154status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
155{
156 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
157 status_t err = UNKNOWN_ERROR;
158 const sp<IMediaPlayerService>& service(getMediaPlayerService());
159 if (service != 0) {
Eric Laurenta514bdb2010-06-21 09:27:30 -0700160 sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length, mAudioSessionId));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800161 err = setDataSource(player);
162 }
163 return err;
164}
165
Nicolas Catania1d187f12009-05-12 23:25:55 -0700166status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
167{
168 Mutex::Autolock _l(mLock);
Nicolas Catania40234932010-03-10 10:41:04 -0800169 const bool hasBeenInitialized =
170 (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
171 ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
172 if ((mPlayer != NULL) && hasBeenInitialized) {
Nicolas Catania1d187f12009-05-12 23:25:55 -0700173 LOGV("invoke %d", request.dataSize());
174 return mPlayer->invoke(request, reply);
175 }
176 LOGE("invoke failed: wrong state %X", mCurrentState);
177 return INVALID_OPERATION;
178}
179
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700180status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
181{
182 LOGD("setMetadataFilter");
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700183 Mutex::Autolock lock(mLock);
184 if (mPlayer == NULL) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700185 return NO_INIT;
186 }
187 return mPlayer->setMetadataFilter(filter);
188}
Nicolas Catania1d187f12009-05-12 23:25:55 -0700189
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700190status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
191{
192 LOGD("getMetadata");
193 Mutex::Autolock lock(mLock);
194 if (mPlayer == NULL) {
195 return NO_INIT;
196 }
197 return mPlayer->getMetadata(update_only, apply_filter, metadata);
198}
199
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700200void MediaPlayer::disconnectNativeWindow() {
201 if (mConnectedWindow != NULL) {
202 status_t err = native_window_disconnect(mConnectedWindow.get(),
203 NATIVE_WINDOW_API_MEDIA);
204
205 if (err != OK) {
206 LOGW("native_window_disconnect returned an error: %s (%d)",
207 strerror(-err), err);
208 }
209 }
210 mConnectedWindow.clear();
211}
212
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800213status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
214{
215 LOGV("setVideoSurface");
216 Mutex::Autolock _l(mLock);
217 if (mPlayer == 0) return NO_INIT;
Andreas Huber5daeb122010-08-16 08:49:37 -0700218
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700219 sp<IBinder> binder(surface == NULL ? NULL : surface->asBinder());
220 if (mConnectedWindowBinder == binder) {
221 return OK;
222 }
223
224 if (surface != NULL) {
225 status_t err = native_window_connect(surface.get(),
226 NATIVE_WINDOW_API_MEDIA);
227
228 if (err != OK) {
229 // Note that we must do the reset before disconnecting from the ANW.
230 // Otherwise queue/dequeue calls could be made on the disconnected
231 // ANW, which may result in errors.
232 reset_l();
233
234 disconnectNativeWindow();
235
236 return err;
237 }
238 }
239
240 // Note that we must set the player's new surface before disconnecting the
241 // old one. Otherwise queue/dequeue calls could be made on the disconnected
242 // ANW, which may result in errors.
243 status_t err = mPlayer->setVideoSurface(surface);
244
245 disconnectNativeWindow();
246
247 mConnectedWindow = surface;
248
249 if (err == OK) {
250 mConnectedWindowBinder = binder;
251 } else {
252 disconnectNativeWindow();
253 }
254
255 return err;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800256}
257
Glenn Kasten11731182011-02-08 17:26:17 -0800258status_t MediaPlayer::setVideoSurfaceTexture(
259 const sp<ISurfaceTexture>& surfaceTexture)
260{
261 LOGV("setVideoSurfaceTexture");
262 Mutex::Autolock _l(mLock);
263 if (mPlayer == 0) return NO_INIT;
264
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700265 sp<IBinder> binder(surfaceTexture == NULL ? NULL :
266 surfaceTexture->asBinder());
267 if (mConnectedWindowBinder == binder) {
268 return OK;
269 }
270
271 sp<ANativeWindow> anw;
272 if (surfaceTexture != NULL) {
273 anw = new SurfaceTextureClient(surfaceTexture);
274 status_t err = native_window_connect(anw.get(),
275 NATIVE_WINDOW_API_MEDIA);
276
277 if (err != OK) {
278 // Note that we must do the reset before disconnecting from the ANW.
279 // Otherwise queue/dequeue calls could be made on the disconnected
280 // ANW, which may result in errors.
281 reset_l();
282
283 disconnectNativeWindow();
284
285 return err;
286 }
287 }
288
289 // Note that we must set the player's new SurfaceTexture before
290 // disconnecting the old one. Otherwise queue/dequeue calls could be made
291 // on the disconnected ANW, which may result in errors.
292 status_t err = mPlayer->setVideoSurfaceTexture(surfaceTexture);
293
294 disconnectNativeWindow();
295
296 mConnectedWindow = anw;
297
298 if (err == OK) {
299 mConnectedWindowBinder = binder;
300 } else {
301 disconnectNativeWindow();
302 }
303
304 return err;
Glenn Kasten11731182011-02-08 17:26:17 -0800305}
306
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800307// must call with lock held
308status_t MediaPlayer::prepareAsync_l()
309{
310 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
311 mPlayer->setAudioStreamType(mStreamType);
312 mCurrentState = MEDIA_PLAYER_PREPARING;
313 return mPlayer->prepareAsync();
314 }
315 LOGE("prepareAsync called in state %d", mCurrentState);
316 return INVALID_OPERATION;
317}
318
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700319// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
320// one defined in the Android framework and one provided by the implementation
321// that generated the error. The sync version of prepare returns only 1 error
322// code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800323status_t MediaPlayer::prepare()
324{
325 LOGV("prepare");
326 Mutex::Autolock _l(mLock);
Jason Sams1af452f2009-03-24 18:45:22 -0700327 mLockThreadId = getThreadId();
328 if (mPrepareSync) {
329 mLockThreadId = 0;
330 return -EALREADY;
331 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800332 mPrepareSync = true;
333 status_t ret = prepareAsync_l();
Jason Sams1af452f2009-03-24 18:45:22 -0700334 if (ret != NO_ERROR) {
335 mLockThreadId = 0;
336 return ret;
337 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800338
339 if (mPrepareSync) {
340 mSignal.wait(mLock); // wait for prepare done
341 mPrepareSync = false;
342 }
343 LOGV("prepare complete - status=%d", mPrepareStatus);
Jason Sams1af452f2009-03-24 18:45:22 -0700344 mLockThreadId = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800345 return mPrepareStatus;
346}
347
348status_t MediaPlayer::prepareAsync()
349{
350 LOGV("prepareAsync");
351 Mutex::Autolock _l(mLock);
352 return prepareAsync_l();
353}
354
355status_t MediaPlayer::start()
356{
357 LOGV("start");
358 Mutex::Autolock _l(mLock);
359 if (mCurrentState & MEDIA_PLAYER_STARTED)
360 return NO_ERROR;
361 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
362 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
363 mPlayer->setLooping(mLoop);
364 mPlayer->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -0700365 mPlayer->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800366 mCurrentState = MEDIA_PLAYER_STARTED;
367 status_t ret = mPlayer->start();
368 if (ret != NO_ERROR) {
369 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
370 } else {
371 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
372 LOGV("playback completed immediately following start()");
373 }
374 }
375 return ret;
376 }
377 LOGE("start called in state %d", mCurrentState);
378 return INVALID_OPERATION;
379}
380
381status_t MediaPlayer::stop()
382{
383 LOGV("stop");
384 Mutex::Autolock _l(mLock);
385 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
386 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
387 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
388 status_t ret = mPlayer->stop();
389 if (ret != NO_ERROR) {
390 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
391 } else {
392 mCurrentState = MEDIA_PLAYER_STOPPED;
393 }
394 return ret;
395 }
396 LOGE("stop called in state %d", mCurrentState);
397 return INVALID_OPERATION;
398}
399
400status_t MediaPlayer::pause()
401{
402 LOGV("pause");
403 Mutex::Autolock _l(mLock);
Marco Nelissen698f4762010-02-26 13:16:23 -0800404 if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800405 return NO_ERROR;
406 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
407 status_t ret = mPlayer->pause();
408 if (ret != NO_ERROR) {
409 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
410 } else {
411 mCurrentState = MEDIA_PLAYER_PAUSED;
412 }
413 return ret;
414 }
415 LOGE("pause called in state %d", mCurrentState);
416 return INVALID_OPERATION;
417}
418
419bool MediaPlayer::isPlaying()
420{
421 Mutex::Autolock _l(mLock);
422 if (mPlayer != 0) {
423 bool temp = false;
424 mPlayer->isPlaying(&temp);
425 LOGV("isPlaying: %d", temp);
426 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
427 LOGE("internal/external state mismatch corrected");
428 mCurrentState = MEDIA_PLAYER_PAUSED;
429 }
430 return temp;
431 }
432 LOGV("isPlaying: no active player");
433 return false;
434}
435
436status_t MediaPlayer::getVideoWidth(int *w)
437{
438 LOGV("getVideoWidth");
439 Mutex::Autolock _l(mLock);
440 if (mPlayer == 0) return INVALID_OPERATION;
441 *w = mVideoWidth;
442 return NO_ERROR;
443}
444
445status_t MediaPlayer::getVideoHeight(int *h)
446{
447 LOGV("getVideoHeight");
448 Mutex::Autolock _l(mLock);
449 if (mPlayer == 0) return INVALID_OPERATION;
450 *h = mVideoHeight;
451 return NO_ERROR;
452}
453
454status_t MediaPlayer::getCurrentPosition(int *msec)
455{
456 LOGV("getCurrentPosition");
457 Mutex::Autolock _l(mLock);
458 if (mPlayer != 0) {
459 if (mCurrentPosition >= 0) {
460 LOGV("Using cached seek position: %d", mCurrentPosition);
461 *msec = mCurrentPosition;
462 return NO_ERROR;
463 }
464 return mPlayer->getCurrentPosition(msec);
465 }
466 return INVALID_OPERATION;
467}
468
469status_t MediaPlayer::getDuration_l(int *msec)
470{
471 LOGV("getDuration");
472 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
473 if (mPlayer != 0 && isValidState) {
474 status_t ret = NO_ERROR;
475 if (mDuration <= 0)
476 ret = mPlayer->getDuration(&mDuration);
477 if (msec)
478 *msec = mDuration;
479 return ret;
480 }
481 LOGE("Attempt to call getDuration without a valid mediaplayer");
482 return INVALID_OPERATION;
483}
484
485status_t MediaPlayer::getDuration(int *msec)
486{
487 Mutex::Autolock _l(mLock);
488 return getDuration_l(msec);
489}
490
491status_t MediaPlayer::seekTo_l(int msec)
492{
493 LOGV("seekTo %d", msec);
494 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
495 if ( msec < 0 ) {
496 LOGW("Attempt to seek to invalid position: %d", msec);
497 msec = 0;
498 } else if ((mDuration > 0) && (msec > mDuration)) {
499 LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
500 msec = mDuration;
501 }
502 // cache duration
503 mCurrentPosition = msec;
504 if (mSeekPosition < 0) {
505 getDuration_l(NULL);
506 mSeekPosition = msec;
507 return mPlayer->seekTo(msec);
508 }
509 else {
510 LOGV("Seek in progress - queue up seekTo[%d]", msec);
511 return NO_ERROR;
512 }
513 }
514 LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
515 return INVALID_OPERATION;
516}
517
518status_t MediaPlayer::seekTo(int msec)
519{
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700520 mLockThreadId = getThreadId();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800521 Mutex::Autolock _l(mLock);
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700522 status_t result = seekTo_l(msec);
523 mLockThreadId = 0;
524
525 return result;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800526}
527
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700528status_t MediaPlayer::reset_l()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800529{
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800530 mLoop = false;
531 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
532 mPrepareSync = false;
533 if (mPlayer != 0) {
534 status_t ret = mPlayer->reset();
535 if (ret != NO_ERROR) {
536 LOGE("reset() failed with return code (%d)", ret);
537 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
538 } else {
539 mCurrentState = MEDIA_PLAYER_IDLE;
540 }
James Donga1680bc2010-11-18 12:23:58 -0800541 // setDataSource has to be called again to create a
542 // new mediaplayer.
543 mPlayer = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800544 return ret;
545 }
546 clear_l();
547 return NO_ERROR;
548}
549
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700550status_t MediaPlayer::reset()
551{
552 LOGV("reset");
553 Mutex::Autolock _l(mLock);
554 return reset_l();
555}
556
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800557status_t MediaPlayer::setAudioStreamType(int type)
558{
559 LOGV("MediaPlayer::setAudioStreamType");
560 Mutex::Autolock _l(mLock);
561 if (mStreamType == type) return NO_ERROR;
562 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
563 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
564 // Can't change the stream type after prepare
565 LOGE("setAudioStream called in state %d", mCurrentState);
566 return INVALID_OPERATION;
567 }
568 // cache
569 mStreamType = type;
570 return OK;
571}
572
573status_t MediaPlayer::setLooping(int loop)
574{
575 LOGV("MediaPlayer::setLooping");
576 Mutex::Autolock _l(mLock);
577 mLoop = (loop != 0);
578 if (mPlayer != 0) {
579 return mPlayer->setLooping(loop);
580 }
581 return OK;
582}
583
584bool MediaPlayer::isLooping() {
585 LOGV("isLooping");
586 Mutex::Autolock _l(mLock);
587 if (mPlayer != 0) {
588 return mLoop;
589 }
590 LOGV("isLooping: no active player");
591 return false;
592}
593
594status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
595{
596 LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
597 Mutex::Autolock _l(mLock);
598 mLeftVolume = leftVolume;
599 mRightVolume = rightVolume;
600 if (mPlayer != 0) {
601 return mPlayer->setVolume(leftVolume, rightVolume);
602 }
603 return OK;
604}
605
Eric Laurenta514bdb2010-06-21 09:27:30 -0700606status_t MediaPlayer::setAudioSessionId(int sessionId)
607{
608 LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
609 Mutex::Autolock _l(mLock);
610 if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
611 LOGE("setAudioSessionId called in state %d", mCurrentState);
612 return INVALID_OPERATION;
613 }
614 if (sessionId < 0) {
615 return BAD_VALUE;
616 }
617 mAudioSessionId = sessionId;
618 return NO_ERROR;
619}
620
621int MediaPlayer::getAudioSessionId()
622{
623 Mutex::Autolock _l(mLock);
624 return mAudioSessionId;
625}
626
Eric Laurent2beeb502010-07-16 07:43:46 -0700627status_t MediaPlayer::setAuxEffectSendLevel(float level)
628{
629 LOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
630 Mutex::Autolock _l(mLock);
631 mSendLevel = level;
632 if (mPlayer != 0) {
633 return mPlayer->setAuxEffectSendLevel(level);
634 }
635 return OK;
636}
637
638status_t MediaPlayer::attachAuxEffect(int effectId)
639{
640 LOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
641 Mutex::Autolock _l(mLock);
642 if (mPlayer == 0 ||
643 (mCurrentState & MEDIA_PLAYER_IDLE) ||
644 (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
645 LOGE("attachAuxEffect called in state %d", mCurrentState);
646 return INVALID_OPERATION;
647 }
648
649 return mPlayer->attachAuxEffect(effectId);
650}
651
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700652status_t MediaPlayer::setParameter(int key, const Parcel& request)
653{
654 LOGV("MediaPlayer::setParameter(%d)", key);
655 Mutex::Autolock _l(mLock);
656 if (mPlayer != NULL) {
657 return mPlayer->setParameter(key, request);
658 }
659 LOGV("setParameter: no active player");
660 return INVALID_OPERATION;
661}
662
663status_t MediaPlayer::getParameter(int key, Parcel *reply)
664{
665 LOGV("MediaPlayer::getParameter(%d)", key);
666 Mutex::Autolock _l(mLock);
667 if (mPlayer != NULL) {
668 return mPlayer->getParameter(key, reply);
669 }
670 LOGV("getParameter: no active player");
671 return INVALID_OPERATION;
672}
673
Gloria Wangb483c472011-04-11 17:23:27 -0700674void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800675{
676 LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
677 bool send = true;
Jason Sams1af452f2009-03-24 18:45:22 -0700678 bool locked = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800679
680 // TODO: In the future, we might be on the same thread if the app is
681 // running in the same process as the media server. In that case,
682 // this will deadlock.
Nicolas Catania66095182009-06-11 16:33:49 -0700683 //
Jason Sams1af452f2009-03-24 18:45:22 -0700684 // The threadId hack below works around this for the care of prepare
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700685 // and seekTo within the same process.
686 // FIXME: Remember, this is a hack, it's not even a hack that is applied
687 // consistently for all use-cases, this needs to be revisited.
Jason Sams1af452f2009-03-24 18:45:22 -0700688 if (mLockThreadId != getThreadId()) {
689 mLock.lock();
690 locked = true;
Nicolas Catania66095182009-06-11 16:33:49 -0700691 }
Jason Sams1af452f2009-03-24 18:45:22 -0700692
Eric Laurent3b268442010-08-03 07:49:49 -0700693 // Allows calls from JNI in idle state to notify errors
694 if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800695 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Sams1af452f2009-03-24 18:45:22 -0700696 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800697 return;
698 }
699
700 switch (msg) {
701 case MEDIA_NOP: // interface test message
702 break;
703 case MEDIA_PREPARED:
704 LOGV("prepared");
705 mCurrentState = MEDIA_PLAYER_PREPARED;
706 if (mPrepareSync) {
707 LOGV("signal application thread");
708 mPrepareSync = false;
709 mPrepareStatus = NO_ERROR;
710 mSignal.signal();
711 }
712 break;
713 case MEDIA_PLAYBACK_COMPLETE:
714 LOGV("playback complete");
Marco Nelissen1c1503c2010-09-17 15:04:01 -0700715 if (mCurrentState == MEDIA_PLAYER_IDLE) {
716 LOGE("playback complete in idle state");
717 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800718 if (!mLoop) {
719 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
720 }
721 break;
722 case MEDIA_ERROR:
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700723 // Always log errors.
724 // ext1: Media framework error code.
725 // ext2: Implementation dependant error code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800726 LOGE("error (%d, %d)", ext1, ext2);
727 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
728 if (mPrepareSync)
729 {
730 LOGV("signal application thread");
731 mPrepareSync = false;
732 mPrepareStatus = ext1;
733 mSignal.signal();
734 send = false;
735 }
736 break;
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700737 case MEDIA_INFO:
738 // ext1: Media framework error code.
739 // ext2: Implementation dependant error code.
Andreas Huber145e68f2011-01-11 15:05:28 -0800740 if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
741 LOGW("info/warning (%d, %d)", ext1, ext2);
742 }
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700743 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800744 case MEDIA_SEEK_COMPLETE:
745 LOGV("Received seek complete");
746 if (mSeekPosition != mCurrentPosition) {
747 LOGV("Executing queued seekTo(%d)", mSeekPosition);
748 mSeekPosition = -1;
749 seekTo_l(mCurrentPosition);
750 }
751 else {
752 LOGV("All seeks complete - return to regularly scheduled program");
753 mCurrentPosition = mSeekPosition = -1;
754 }
755 break;
756 case MEDIA_BUFFERING_UPDATE:
757 LOGV("buffering %d", ext1);
758 break;
759 case MEDIA_SET_VIDEO_SIZE:
760 LOGV("New video size %d x %d", ext1, ext2);
761 mVideoWidth = ext1;
762 mVideoHeight = ext2;
763 break;
Gloria Wangb483c472011-04-11 17:23:27 -0700764 case MEDIA_TIMED_TEXT:
765 LOGV("Received timed text message");
766 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800767 default:
768 LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
769 break;
770 }
771
772 sp<MediaPlayerListener> listener = mListener;
Jason Sams1af452f2009-03-24 18:45:22 -0700773 if (locked) mLock.unlock();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800774
775 // this prevents re-entrant calls into client code
776 if ((listener != 0) && send) {
777 Mutex::Autolock _l(mNotifyLock);
778 LOGV("callback application");
Gloria Wangb483c472011-04-11 17:23:27 -0700779 listener->notify(msg, ext1, ext2, obj);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800780 LOGV("back from callback");
781 }
782}
783
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800784/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
785{
786 LOGV("decode(%s)", url);
787 sp<IMemory> p;
788 const sp<IMediaPlayerService>& service = getMediaPlayerService();
789 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800790 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800791 } else {
792 LOGE("Unable to locate media service");
793 }
794 return p;
795
796}
797
James Dongdd172fc2010-01-15 18:13:58 -0800798void MediaPlayer::died()
799{
800 LOGV("died");
801 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
802}
803
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800804/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
805{
806 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
807 sp<IMemory> p;
808 const sp<IMediaPlayerService>& service = getMediaPlayerService();
809 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800810 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800811 } else {
812 LOGE("Unable to locate media service");
813 }
814 return p;
815
816}
817
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800818}; // namespace android