blob: f1a60417bb6cb10a143f1ed23bdee66edaab6b5c [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) {
James Dongfada58a2011-07-21 17:32:55 -0700229 LOGE("setVideoSurface failed: %d", err);
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700230 // Note that we must do the reset before disconnecting from the ANW.
231 // Otherwise queue/dequeue calls could be made on the disconnected
232 // ANW, which may result in errors.
233 reset_l();
234
235 disconnectNativeWindow();
236
237 return err;
238 }
239 }
240
241 // Note that we must set the player's new surface before disconnecting the
242 // old one. Otherwise queue/dequeue calls could be made on the disconnected
243 // ANW, which may result in errors.
244 status_t err = mPlayer->setVideoSurface(surface);
245
246 disconnectNativeWindow();
247
248 mConnectedWindow = surface;
249
250 if (err == OK) {
251 mConnectedWindowBinder = binder;
252 } else {
253 disconnectNativeWindow();
254 }
255
256 return err;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800257}
258
Glenn Kasten11731182011-02-08 17:26:17 -0800259status_t MediaPlayer::setVideoSurfaceTexture(
260 const sp<ISurfaceTexture>& surfaceTexture)
261{
262 LOGV("setVideoSurfaceTexture");
263 Mutex::Autolock _l(mLock);
264 if (mPlayer == 0) return NO_INIT;
265
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700266 sp<IBinder> binder(surfaceTexture == NULL ? NULL :
267 surfaceTexture->asBinder());
268 if (mConnectedWindowBinder == binder) {
269 return OK;
270 }
271
272 sp<ANativeWindow> anw;
273 if (surfaceTexture != NULL) {
274 anw = new SurfaceTextureClient(surfaceTexture);
275 status_t err = native_window_connect(anw.get(),
276 NATIVE_WINDOW_API_MEDIA);
277
278 if (err != OK) {
James Dongfada58a2011-07-21 17:32:55 -0700279 LOGE("setVideoSurfaceTexture failed: %d", err);
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700280 // Note that we must do the reset before disconnecting from the ANW.
281 // Otherwise queue/dequeue calls could be made on the disconnected
282 // ANW, which may result in errors.
283 reset_l();
284
285 disconnectNativeWindow();
286
287 return err;
288 }
289 }
290
291 // Note that we must set the player's new SurfaceTexture before
292 // disconnecting the old one. Otherwise queue/dequeue calls could be made
293 // on the disconnected ANW, which may result in errors.
294 status_t err = mPlayer->setVideoSurfaceTexture(surfaceTexture);
295
296 disconnectNativeWindow();
297
298 mConnectedWindow = anw;
299
300 if (err == OK) {
301 mConnectedWindowBinder = binder;
302 } else {
303 disconnectNativeWindow();
304 }
305
306 return err;
Glenn Kasten11731182011-02-08 17:26:17 -0800307}
308
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800309// must call with lock held
310status_t MediaPlayer::prepareAsync_l()
311{
312 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
313 mPlayer->setAudioStreamType(mStreamType);
314 mCurrentState = MEDIA_PLAYER_PREPARING;
315 return mPlayer->prepareAsync();
316 }
317 LOGE("prepareAsync called in state %d", mCurrentState);
318 return INVALID_OPERATION;
319}
320
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700321// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
322// one defined in the Android framework and one provided by the implementation
323// that generated the error. The sync version of prepare returns only 1 error
324// code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800325status_t MediaPlayer::prepare()
326{
327 LOGV("prepare");
328 Mutex::Autolock _l(mLock);
Jason Sams1af452f2009-03-24 18:45:22 -0700329 mLockThreadId = getThreadId();
330 if (mPrepareSync) {
331 mLockThreadId = 0;
332 return -EALREADY;
333 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800334 mPrepareSync = true;
335 status_t ret = prepareAsync_l();
Jason Sams1af452f2009-03-24 18:45:22 -0700336 if (ret != NO_ERROR) {
337 mLockThreadId = 0;
338 return ret;
339 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800340
341 if (mPrepareSync) {
342 mSignal.wait(mLock); // wait for prepare done
343 mPrepareSync = false;
344 }
345 LOGV("prepare complete - status=%d", mPrepareStatus);
Jason Sams1af452f2009-03-24 18:45:22 -0700346 mLockThreadId = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800347 return mPrepareStatus;
348}
349
350status_t MediaPlayer::prepareAsync()
351{
352 LOGV("prepareAsync");
353 Mutex::Autolock _l(mLock);
354 return prepareAsync_l();
355}
356
357status_t MediaPlayer::start()
358{
359 LOGV("start");
360 Mutex::Autolock _l(mLock);
361 if (mCurrentState & MEDIA_PLAYER_STARTED)
362 return NO_ERROR;
363 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
364 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
365 mPlayer->setLooping(mLoop);
366 mPlayer->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -0700367 mPlayer->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800368 mCurrentState = MEDIA_PLAYER_STARTED;
369 status_t ret = mPlayer->start();
370 if (ret != NO_ERROR) {
371 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
372 } else {
373 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
374 LOGV("playback completed immediately following start()");
375 }
376 }
377 return ret;
378 }
379 LOGE("start called in state %d", mCurrentState);
380 return INVALID_OPERATION;
381}
382
383status_t MediaPlayer::stop()
384{
385 LOGV("stop");
386 Mutex::Autolock _l(mLock);
387 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
388 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
389 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
390 status_t ret = mPlayer->stop();
391 if (ret != NO_ERROR) {
392 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
393 } else {
394 mCurrentState = MEDIA_PLAYER_STOPPED;
395 }
396 return ret;
397 }
398 LOGE("stop called in state %d", mCurrentState);
399 return INVALID_OPERATION;
400}
401
402status_t MediaPlayer::pause()
403{
404 LOGV("pause");
405 Mutex::Autolock _l(mLock);
Marco Nelissen698f4762010-02-26 13:16:23 -0800406 if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800407 return NO_ERROR;
408 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
409 status_t ret = mPlayer->pause();
410 if (ret != NO_ERROR) {
411 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
412 } else {
413 mCurrentState = MEDIA_PLAYER_PAUSED;
414 }
415 return ret;
416 }
417 LOGE("pause called in state %d", mCurrentState);
418 return INVALID_OPERATION;
419}
420
421bool MediaPlayer::isPlaying()
422{
423 Mutex::Autolock _l(mLock);
424 if (mPlayer != 0) {
425 bool temp = false;
426 mPlayer->isPlaying(&temp);
427 LOGV("isPlaying: %d", temp);
428 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
429 LOGE("internal/external state mismatch corrected");
430 mCurrentState = MEDIA_PLAYER_PAUSED;
431 }
432 return temp;
433 }
434 LOGV("isPlaying: no active player");
435 return false;
436}
437
438status_t MediaPlayer::getVideoWidth(int *w)
439{
440 LOGV("getVideoWidth");
441 Mutex::Autolock _l(mLock);
442 if (mPlayer == 0) return INVALID_OPERATION;
443 *w = mVideoWidth;
444 return NO_ERROR;
445}
446
447status_t MediaPlayer::getVideoHeight(int *h)
448{
449 LOGV("getVideoHeight");
450 Mutex::Autolock _l(mLock);
451 if (mPlayer == 0) return INVALID_OPERATION;
452 *h = mVideoHeight;
453 return NO_ERROR;
454}
455
456status_t MediaPlayer::getCurrentPosition(int *msec)
457{
458 LOGV("getCurrentPosition");
459 Mutex::Autolock _l(mLock);
460 if (mPlayer != 0) {
461 if (mCurrentPosition >= 0) {
462 LOGV("Using cached seek position: %d", mCurrentPosition);
463 *msec = mCurrentPosition;
464 return NO_ERROR;
465 }
466 return mPlayer->getCurrentPosition(msec);
467 }
468 return INVALID_OPERATION;
469}
470
471status_t MediaPlayer::getDuration_l(int *msec)
472{
473 LOGV("getDuration");
474 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
475 if (mPlayer != 0 && isValidState) {
476 status_t ret = NO_ERROR;
477 if (mDuration <= 0)
478 ret = mPlayer->getDuration(&mDuration);
479 if (msec)
480 *msec = mDuration;
481 return ret;
482 }
483 LOGE("Attempt to call getDuration without a valid mediaplayer");
484 return INVALID_OPERATION;
485}
486
487status_t MediaPlayer::getDuration(int *msec)
488{
489 Mutex::Autolock _l(mLock);
490 return getDuration_l(msec);
491}
492
493status_t MediaPlayer::seekTo_l(int msec)
494{
495 LOGV("seekTo %d", msec);
496 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
497 if ( msec < 0 ) {
498 LOGW("Attempt to seek to invalid position: %d", msec);
499 msec = 0;
500 } else if ((mDuration > 0) && (msec > mDuration)) {
501 LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
502 msec = mDuration;
503 }
504 // cache duration
505 mCurrentPosition = msec;
506 if (mSeekPosition < 0) {
507 getDuration_l(NULL);
508 mSeekPosition = msec;
509 return mPlayer->seekTo(msec);
510 }
511 else {
512 LOGV("Seek in progress - queue up seekTo[%d]", msec);
513 return NO_ERROR;
514 }
515 }
516 LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
517 return INVALID_OPERATION;
518}
519
520status_t MediaPlayer::seekTo(int msec)
521{
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700522 mLockThreadId = getThreadId();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800523 Mutex::Autolock _l(mLock);
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700524 status_t result = seekTo_l(msec);
525 mLockThreadId = 0;
526
527 return result;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800528}
529
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700530status_t MediaPlayer::reset_l()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800531{
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800532 mLoop = false;
533 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
534 mPrepareSync = false;
535 if (mPlayer != 0) {
536 status_t ret = mPlayer->reset();
537 if (ret != NO_ERROR) {
538 LOGE("reset() failed with return code (%d)", ret);
539 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
540 } else {
541 mCurrentState = MEDIA_PLAYER_IDLE;
542 }
James Donga1680bc2010-11-18 12:23:58 -0800543 // setDataSource has to be called again to create a
544 // new mediaplayer.
545 mPlayer = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800546 return ret;
547 }
548 clear_l();
549 return NO_ERROR;
550}
551
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700552status_t MediaPlayer::reset()
553{
554 LOGV("reset");
555 Mutex::Autolock _l(mLock);
556 return reset_l();
557}
558
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800559status_t MediaPlayer::setAudioStreamType(int type)
560{
561 LOGV("MediaPlayer::setAudioStreamType");
562 Mutex::Autolock _l(mLock);
563 if (mStreamType == type) return NO_ERROR;
564 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
565 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
566 // Can't change the stream type after prepare
567 LOGE("setAudioStream called in state %d", mCurrentState);
568 return INVALID_OPERATION;
569 }
570 // cache
571 mStreamType = type;
572 return OK;
573}
574
575status_t MediaPlayer::setLooping(int loop)
576{
577 LOGV("MediaPlayer::setLooping");
578 Mutex::Autolock _l(mLock);
579 mLoop = (loop != 0);
580 if (mPlayer != 0) {
581 return mPlayer->setLooping(loop);
582 }
583 return OK;
584}
585
586bool MediaPlayer::isLooping() {
587 LOGV("isLooping");
588 Mutex::Autolock _l(mLock);
589 if (mPlayer != 0) {
590 return mLoop;
591 }
592 LOGV("isLooping: no active player");
593 return false;
594}
595
596status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
597{
598 LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
599 Mutex::Autolock _l(mLock);
600 mLeftVolume = leftVolume;
601 mRightVolume = rightVolume;
602 if (mPlayer != 0) {
603 return mPlayer->setVolume(leftVolume, rightVolume);
604 }
605 return OK;
606}
607
Eric Laurenta514bdb2010-06-21 09:27:30 -0700608status_t MediaPlayer::setAudioSessionId(int sessionId)
609{
610 LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
611 Mutex::Autolock _l(mLock);
612 if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
613 LOGE("setAudioSessionId called in state %d", mCurrentState);
614 return INVALID_OPERATION;
615 }
616 if (sessionId < 0) {
617 return BAD_VALUE;
618 }
619 mAudioSessionId = sessionId;
620 return NO_ERROR;
621}
622
623int MediaPlayer::getAudioSessionId()
624{
625 Mutex::Autolock _l(mLock);
626 return mAudioSessionId;
627}
628
Eric Laurent2beeb502010-07-16 07:43:46 -0700629status_t MediaPlayer::setAuxEffectSendLevel(float level)
630{
631 LOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
632 Mutex::Autolock _l(mLock);
633 mSendLevel = level;
634 if (mPlayer != 0) {
635 return mPlayer->setAuxEffectSendLevel(level);
636 }
637 return OK;
638}
639
640status_t MediaPlayer::attachAuxEffect(int effectId)
641{
642 LOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
643 Mutex::Autolock _l(mLock);
644 if (mPlayer == 0 ||
645 (mCurrentState & MEDIA_PLAYER_IDLE) ||
646 (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
647 LOGE("attachAuxEffect called in state %d", mCurrentState);
648 return INVALID_OPERATION;
649 }
650
651 return mPlayer->attachAuxEffect(effectId);
652}
653
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700654status_t MediaPlayer::setParameter(int key, const Parcel& request)
655{
656 LOGV("MediaPlayer::setParameter(%d)", key);
657 Mutex::Autolock _l(mLock);
658 if (mPlayer != NULL) {
659 return mPlayer->setParameter(key, request);
660 }
661 LOGV("setParameter: no active player");
662 return INVALID_OPERATION;
663}
664
665status_t MediaPlayer::getParameter(int key, Parcel *reply)
666{
667 LOGV("MediaPlayer::getParameter(%d)", key);
668 Mutex::Autolock _l(mLock);
669 if (mPlayer != NULL) {
670 return mPlayer->getParameter(key, reply);
671 }
672 LOGV("getParameter: no active player");
673 return INVALID_OPERATION;
674}
675
Gloria Wangb483c472011-04-11 17:23:27 -0700676void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800677{
678 LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
679 bool send = true;
Jason Sams1af452f2009-03-24 18:45:22 -0700680 bool locked = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800681
682 // TODO: In the future, we might be on the same thread if the app is
683 // running in the same process as the media server. In that case,
684 // this will deadlock.
Nicolas Catania66095182009-06-11 16:33:49 -0700685 //
Jason Sams1af452f2009-03-24 18:45:22 -0700686 // The threadId hack below works around this for the care of prepare
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700687 // and seekTo within the same process.
688 // FIXME: Remember, this is a hack, it's not even a hack that is applied
689 // consistently for all use-cases, this needs to be revisited.
Jason Sams1af452f2009-03-24 18:45:22 -0700690 if (mLockThreadId != getThreadId()) {
691 mLock.lock();
692 locked = true;
Nicolas Catania66095182009-06-11 16:33:49 -0700693 }
Jason Sams1af452f2009-03-24 18:45:22 -0700694
Eric Laurent3b268442010-08-03 07:49:49 -0700695 // Allows calls from JNI in idle state to notify errors
696 if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800697 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Sams1af452f2009-03-24 18:45:22 -0700698 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800699 return;
700 }
701
702 switch (msg) {
703 case MEDIA_NOP: // interface test message
704 break;
705 case MEDIA_PREPARED:
706 LOGV("prepared");
707 mCurrentState = MEDIA_PLAYER_PREPARED;
708 if (mPrepareSync) {
709 LOGV("signal application thread");
710 mPrepareSync = false;
711 mPrepareStatus = NO_ERROR;
712 mSignal.signal();
713 }
714 break;
715 case MEDIA_PLAYBACK_COMPLETE:
716 LOGV("playback complete");
Marco Nelissen1c1503c2010-09-17 15:04:01 -0700717 if (mCurrentState == MEDIA_PLAYER_IDLE) {
718 LOGE("playback complete in idle state");
719 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800720 if (!mLoop) {
721 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
722 }
723 break;
724 case MEDIA_ERROR:
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700725 // Always log errors.
726 // ext1: Media framework error code.
727 // ext2: Implementation dependant error code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800728 LOGE("error (%d, %d)", ext1, ext2);
729 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
730 if (mPrepareSync)
731 {
732 LOGV("signal application thread");
733 mPrepareSync = false;
734 mPrepareStatus = ext1;
735 mSignal.signal();
736 send = false;
737 }
738 break;
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700739 case MEDIA_INFO:
740 // ext1: Media framework error code.
741 // ext2: Implementation dependant error code.
Andreas Huber145e68f2011-01-11 15:05:28 -0800742 if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
743 LOGW("info/warning (%d, %d)", ext1, ext2);
744 }
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700745 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800746 case MEDIA_SEEK_COMPLETE:
747 LOGV("Received seek complete");
748 if (mSeekPosition != mCurrentPosition) {
749 LOGV("Executing queued seekTo(%d)", mSeekPosition);
750 mSeekPosition = -1;
751 seekTo_l(mCurrentPosition);
752 }
753 else {
754 LOGV("All seeks complete - return to regularly scheduled program");
755 mCurrentPosition = mSeekPosition = -1;
756 }
757 break;
758 case MEDIA_BUFFERING_UPDATE:
759 LOGV("buffering %d", ext1);
760 break;
761 case MEDIA_SET_VIDEO_SIZE:
762 LOGV("New video size %d x %d", ext1, ext2);
763 mVideoWidth = ext1;
764 mVideoHeight = ext2;
765 break;
Gloria Wangb483c472011-04-11 17:23:27 -0700766 case MEDIA_TIMED_TEXT:
767 LOGV("Received timed text message");
768 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800769 default:
770 LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
771 break;
772 }
773
774 sp<MediaPlayerListener> listener = mListener;
Jason Sams1af452f2009-03-24 18:45:22 -0700775 if (locked) mLock.unlock();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800776
777 // this prevents re-entrant calls into client code
778 if ((listener != 0) && send) {
779 Mutex::Autolock _l(mNotifyLock);
780 LOGV("callback application");
Gloria Wangb483c472011-04-11 17:23:27 -0700781 listener->notify(msg, ext1, ext2, obj);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800782 LOGV("back from callback");
783 }
784}
785
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800786/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
787{
788 LOGV("decode(%s)", url);
789 sp<IMemory> p;
790 const sp<IMediaPlayerService>& service = getMediaPlayerService();
791 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800792 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800793 } else {
794 LOGE("Unable to locate media service");
795 }
796 return p;
797
798}
799
James Dongdd172fc2010-01-15 18:13:58 -0800800void MediaPlayer::died()
801{
802 LOGV("died");
803 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
804}
805
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800806/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
807{
808 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
809 sp<IMemory> p;
810 const sp<IMediaPlayerService>& service = getMediaPlayerService();
811 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800812 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800813 } else {
814 LOGE("Unable to locate media service");
815 }
816 return p;
817
818}
819
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800820}; // namespace android