blob: ed6e3c7aa7a587ae5662f5eb22ceb0b7d4fbedab [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 }
Jamie Gennisbea47bc2011-07-19 14:50:43 -070087
88 disconnectNativeWindow();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080089}
90
91// always call with lock held
92void MediaPlayer::clear_l()
93{
94 mDuration = -1;
95 mCurrentPosition = -1;
96 mSeekPosition = -1;
97 mVideoWidth = mVideoHeight = 0;
98}
99
100status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
101{
102 LOGV("setListener");
103 Mutex::Autolock _l(mLock);
104 mListener = listener;
105 return NO_ERROR;
106}
107
108
109status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
110{
111 status_t err = UNKNOWN_ERROR;
112 sp<IMediaPlayer> p;
113 { // scope for the lock
114 Mutex::Autolock _l(mLock);
115
Marco Nelissen83ff1432010-03-10 10:53:16 -0800116 if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
117 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800118 LOGE("setDataSource called in state %d", mCurrentState);
119 return INVALID_OPERATION;
120 }
121
122 clear_l();
123 p = mPlayer;
124 mPlayer = player;
125 if (player != 0) {
126 mCurrentState = MEDIA_PLAYER_INITIALIZED;
127 err = NO_ERROR;
128 } else {
129 LOGE("Unable to to create media player");
130 }
131 }
132
133 if (p != 0) {
134 p->disconnect();
135 }
136
137 return err;
138}
139
Andreas Huber2db84552010-01-28 11:19:57 -0800140status_t MediaPlayer::setDataSource(
141 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800142{
143 LOGV("setDataSource(%s)", url);
144 status_t err = BAD_VALUE;
145 if (url != NULL) {
146 const sp<IMediaPlayerService>& service(getMediaPlayerService());
147 if (service != 0) {
Andreas Huber2db84552010-01-28 11:19:57 -0800148 sp<IMediaPlayer> player(
Eric Laurenta514bdb2010-06-21 09:27:30 -0700149 service->create(getpid(), this, url, headers, mAudioSessionId));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800150 err = setDataSource(player);
151 }
152 }
153 return err;
154}
155
156status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
157{
158 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
159 status_t err = UNKNOWN_ERROR;
160 const sp<IMediaPlayerService>& service(getMediaPlayerService());
161 if (service != 0) {
Eric Laurenta514bdb2010-06-21 09:27:30 -0700162 sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length, mAudioSessionId));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800163 err = setDataSource(player);
164 }
165 return err;
166}
167
Nicolas Catania1d187f12009-05-12 23:25:55 -0700168status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
169{
170 Mutex::Autolock _l(mLock);
Nicolas Catania40234932010-03-10 10:41:04 -0800171 const bool hasBeenInitialized =
172 (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
173 ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
174 if ((mPlayer != NULL) && hasBeenInitialized) {
Nicolas Catania1d187f12009-05-12 23:25:55 -0700175 LOGV("invoke %d", request.dataSize());
176 return mPlayer->invoke(request, reply);
177 }
178 LOGE("invoke failed: wrong state %X", mCurrentState);
179 return INVALID_OPERATION;
180}
181
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700182status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
183{
184 LOGD("setMetadataFilter");
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700185 Mutex::Autolock lock(mLock);
186 if (mPlayer == NULL) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700187 return NO_INIT;
188 }
189 return mPlayer->setMetadataFilter(filter);
190}
Nicolas Catania1d187f12009-05-12 23:25:55 -0700191
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700192status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
193{
194 LOGD("getMetadata");
195 Mutex::Autolock lock(mLock);
196 if (mPlayer == NULL) {
197 return NO_INIT;
198 }
199 return mPlayer->getMetadata(update_only, apply_filter, metadata);
200}
201
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700202void MediaPlayer::disconnectNativeWindow() {
203 if (mConnectedWindow != NULL) {
204 status_t err = native_window_disconnect(mConnectedWindow.get(),
205 NATIVE_WINDOW_API_MEDIA);
206
207 if (err != OK) {
208 LOGW("native_window_disconnect returned an error: %s (%d)",
209 strerror(-err), err);
210 }
211 }
212 mConnectedWindow.clear();
213}
214
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800215status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
216{
217 LOGV("setVideoSurface");
218 Mutex::Autolock _l(mLock);
219 if (mPlayer == 0) return NO_INIT;
Andreas Huber5daeb122010-08-16 08:49:37 -0700220
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700221 sp<IBinder> binder(surface == NULL ? NULL : surface->asBinder());
222 if (mConnectedWindowBinder == binder) {
223 return OK;
224 }
225
226 if (surface != NULL) {
227 status_t err = native_window_connect(surface.get(),
228 NATIVE_WINDOW_API_MEDIA);
229
230 if (err != OK) {
231 // Note that we must do the reset before disconnecting from the ANW.
232 // Otherwise queue/dequeue calls could be made on the disconnected
233 // ANW, which may result in errors.
234 reset_l();
235
236 disconnectNativeWindow();
237
238 return err;
239 }
240 }
241
242 // Note that we must set the player's new surface before disconnecting the
243 // old one. Otherwise queue/dequeue calls could be made on the disconnected
244 // ANW, which may result in errors.
245 status_t err = mPlayer->setVideoSurface(surface);
246
247 disconnectNativeWindow();
248
249 mConnectedWindow = surface;
250
251 if (err == OK) {
252 mConnectedWindowBinder = binder;
253 } else {
254 disconnectNativeWindow();
255 }
256
257 return err;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800258}
259
Glenn Kasten11731182011-02-08 17:26:17 -0800260status_t MediaPlayer::setVideoSurfaceTexture(
261 const sp<ISurfaceTexture>& surfaceTexture)
262{
263 LOGV("setVideoSurfaceTexture");
264 Mutex::Autolock _l(mLock);
265 if (mPlayer == 0) return NO_INIT;
266
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700267 sp<IBinder> binder(surfaceTexture == NULL ? NULL :
268 surfaceTexture->asBinder());
269 if (mConnectedWindowBinder == binder) {
270 return OK;
271 }
272
273 sp<ANativeWindow> anw;
274 if (surfaceTexture != NULL) {
275 anw = new SurfaceTextureClient(surfaceTexture);
276 status_t err = native_window_connect(anw.get(),
277 NATIVE_WINDOW_API_MEDIA);
278
279 if (err != OK) {
280 // 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