blob: 3dd9249d4ec48ca63fbee317655947951d271e7d [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* mediaplayer.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaPlayer"
20#include <utils/Log.h>
21
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <fcntl.h>
26
Mathias Agopian07952722009-05-19 19:08:10 -070027#include <binder/IServiceManager.h>
28#include <binder/IPCThreadState.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
Jamie Gennisc85ca5d2011-07-13 12:59:34 -070030#include <gui/SurfaceTextureClient.h>
31
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032#include <media/mediaplayer.h>
33#include <media/AudioTrack.h>
34
Mathias Agopian000479f2010-02-09 17:46:37 -080035#include <surfaceflinger/Surface.h>
36
Mathias Agopian07952722009-05-19 19:08:10 -070037#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
Andreas Huber25643002010-01-28 11:19:57 -080039#include <utils/KeyedVector.h>
40#include <utils/String8.h>
41
Dima Zavin34bb4192011-05-11 14:15:23 -070042#include <system/audio.h>
Jamie Gennisc85ca5d2011-07-13 12:59:34 -070043#include <system/window.h>
Dima Zavin24fc2fb2011-04-19 22:30:36 -070044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045namespace android {
46
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047MediaPlayer::MediaPlayer()
48{
49 LOGV("constructor");
50 mListener = NULL;
51 mCookie = NULL;
52 mDuration = -1;
Dima Zavin24fc2fb2011-04-19 22:30:36 -070053 mStreamType = AUDIO_STREAM_MUSIC;
The Android Open Source Project9066cfe2009-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 Samsebb020a2009-03-24 18:45:22 -070062 mLockThreadId = 0;
Eric Laurent619346f2010-06-21 09:27:30 -070063 mAudioSessionId = AudioSystem::newAudioSessionId();
Eric Laurentb3bdf3f2010-10-07 18:23:03 -070064 mSendLevel = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065}
66
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067MediaPlayer::~MediaPlayer()
68{
69 LOGV("destructor");
The Android Open Source Project9066cfe2009-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 Gennis5129b682011-07-19 14:50:43 -070087
88 disconnectNativeWindow();
The Android Open Source Project9066cfe2009-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 Nelissene44b41b2010-03-10 10:53:16 -0800116 if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
117 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
The Android Open Source Project9066cfe2009-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 Huber25643002010-01-28 11:19:57 -0800140status_t MediaPlayer::setDataSource(
141 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project9066cfe2009-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 Huber25643002010-01-28 11:19:57 -0800148 sp<IMediaPlayer> player(
Eric Laurent619346f2010-06-21 09:27:30 -0700149 service->create(getpid(), this, url, headers, mAudioSessionId));
The Android Open Source Project9066cfe2009-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 Laurent619346f2010-06-21 09:27:30 -0700162 sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length, mAudioSessionId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 err = setDataSource(player);
164 }
165 return err;
166}
167
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700168status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
169{
170 Mutex::Autolock _l(mLock);
Nicolas Catania7bd3d7d2010-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 Catania20cb94e2009-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 Cataniab2c69392009-07-08 08:57:42 -0700182status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
183{
184 LOGD("setMetadataFilter");
Nicolas Catania5d55c712009-07-09 09:21:33 -0700185 Mutex::Autolock lock(mLock);
186 if (mPlayer == NULL) {
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700187 return NO_INIT;
188 }
189 return mPlayer->setMetadataFilter(filter);
190}
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700191
Nicolas Catania5d55c712009-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 Gennisc85ca5d2011-07-13 12:59:34 -0700202void MediaPlayer::disconnectNativeWindow() {
203 if (mConnectedWindow != NULL) {
Mathias Agopian982d2da2011-07-29 17:55:48 -0700204 status_t err = native_window_api_disconnect(mConnectedWindow.get(),
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700205 NATIVE_WINDOW_API_MEDIA);
206
207 if (err != OK) {
Mathias Agopian982d2da2011-07-29 17:55:48 -0700208 LOGW("native_window_api_disconnect returned an error: %s (%d)",
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700209 strerror(-err), err);
210 }
211 }
212 mConnectedWindow.clear();
213}
214
The Android Open Source Project9066cfe2009-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 Hubere3c01832010-08-16 08:49:37 -0700220
Jamie Gennisc85ca5d2011-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) {
Mathias Agopian982d2da2011-07-29 17:55:48 -0700227 status_t err = native_window_api_connect(surface.get(),
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700228 NATIVE_WINDOW_API_MEDIA);
229
230 if (err != OK) {
James Dongce78dc52011-07-21 17:32:55 -0700231 LOGE("setVideoSurface failed: %d", err);
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700232 // Note that we must do the reset before disconnecting from the ANW.
233 // Otherwise queue/dequeue calls could be made on the disconnected
234 // ANW, which may result in errors.
235 reset_l();
236
237 disconnectNativeWindow();
238
239 return err;
240 }
241 }
242
243 // Note that we must set the player's new surface before disconnecting the
244 // old one. Otherwise queue/dequeue calls could be made on the disconnected
245 // ANW, which may result in errors.
246 status_t err = mPlayer->setVideoSurface(surface);
247
248 disconnectNativeWindow();
249
250 mConnectedWindow = surface;
251
252 if (err == OK) {
253 mConnectedWindowBinder = binder;
254 } else {
255 disconnectNativeWindow();
256 }
257
258 return err;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259}
260
Glenn Kastencc562a32011-02-08 17:26:17 -0800261status_t MediaPlayer::setVideoSurfaceTexture(
262 const sp<ISurfaceTexture>& surfaceTexture)
263{
264 LOGV("setVideoSurfaceTexture");
265 Mutex::Autolock _l(mLock);
266 if (mPlayer == 0) return NO_INIT;
267
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700268 sp<IBinder> binder(surfaceTexture == NULL ? NULL :
269 surfaceTexture->asBinder());
270 if (mConnectedWindowBinder == binder) {
271 return OK;
272 }
273
274 sp<ANativeWindow> anw;
275 if (surfaceTexture != NULL) {
276 anw = new SurfaceTextureClient(surfaceTexture);
Mathias Agopian982d2da2011-07-29 17:55:48 -0700277 status_t err = native_window_api_connect(anw.get(),
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700278 NATIVE_WINDOW_API_MEDIA);
279
280 if (err != OK) {
James Dongce78dc52011-07-21 17:32:55 -0700281 LOGE("setVideoSurfaceTexture failed: %d", err);
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700282 // Note that we must do the reset before disconnecting from the ANW.
283 // Otherwise queue/dequeue calls could be made on the disconnected
284 // ANW, which may result in errors.
285 reset_l();
286
287 disconnectNativeWindow();
288
289 return err;
290 }
291 }
292
293 // Note that we must set the player's new SurfaceTexture before
294 // disconnecting the old one. Otherwise queue/dequeue calls could be made
295 // on the disconnected ANW, which may result in errors.
296 status_t err = mPlayer->setVideoSurfaceTexture(surfaceTexture);
297
298 disconnectNativeWindow();
299
300 mConnectedWindow = anw;
301
302 if (err == OK) {
303 mConnectedWindowBinder = binder;
304 } else {
305 disconnectNativeWindow();
306 }
307
308 return err;
Glenn Kastencc562a32011-02-08 17:26:17 -0800309}
310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311// must call with lock held
312status_t MediaPlayer::prepareAsync_l()
313{
314 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
315 mPlayer->setAudioStreamType(mStreamType);
316 mCurrentState = MEDIA_PLAYER_PREPARING;
317 return mPlayer->prepareAsync();
318 }
319 LOGE("prepareAsync called in state %d", mCurrentState);
320 return INVALID_OPERATION;
321}
322
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700323// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
324// one defined in the Android framework and one provided by the implementation
325// that generated the error. The sync version of prepare returns only 1 error
326// code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327status_t MediaPlayer::prepare()
328{
329 LOGV("prepare");
330 Mutex::Autolock _l(mLock);
Jason Samsebb020a2009-03-24 18:45:22 -0700331 mLockThreadId = getThreadId();
332 if (mPrepareSync) {
333 mLockThreadId = 0;
334 return -EALREADY;
335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 mPrepareSync = true;
337 status_t ret = prepareAsync_l();
Jason Samsebb020a2009-03-24 18:45:22 -0700338 if (ret != NO_ERROR) {
339 mLockThreadId = 0;
340 return ret;
341 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342
343 if (mPrepareSync) {
344 mSignal.wait(mLock); // wait for prepare done
345 mPrepareSync = false;
346 }
347 LOGV("prepare complete - status=%d", mPrepareStatus);
Jason Samsebb020a2009-03-24 18:45:22 -0700348 mLockThreadId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 return mPrepareStatus;
350}
351
352status_t MediaPlayer::prepareAsync()
353{
354 LOGV("prepareAsync");
355 Mutex::Autolock _l(mLock);
356 return prepareAsync_l();
357}
358
359status_t MediaPlayer::start()
360{
361 LOGV("start");
362 Mutex::Autolock _l(mLock);
363 if (mCurrentState & MEDIA_PLAYER_STARTED)
364 return NO_ERROR;
365 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
366 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
367 mPlayer->setLooping(mLoop);
368 mPlayer->setVolume(mLeftVolume, mRightVolume);
Eric Laurent7070b362010-07-16 07:43:46 -0700369 mPlayer->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 mCurrentState = MEDIA_PLAYER_STARTED;
371 status_t ret = mPlayer->start();
372 if (ret != NO_ERROR) {
373 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
374 } else {
375 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
376 LOGV("playback completed immediately following start()");
377 }
378 }
379 return ret;
380 }
381 LOGE("start called in state %d", mCurrentState);
382 return INVALID_OPERATION;
383}
384
385status_t MediaPlayer::stop()
386{
387 LOGV("stop");
388 Mutex::Autolock _l(mLock);
389 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
390 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
391 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
392 status_t ret = mPlayer->stop();
393 if (ret != NO_ERROR) {
394 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
395 } else {
396 mCurrentState = MEDIA_PLAYER_STOPPED;
397 }
398 return ret;
399 }
400 LOGE("stop called in state %d", mCurrentState);
401 return INVALID_OPERATION;
402}
403
404status_t MediaPlayer::pause()
405{
406 LOGV("pause");
407 Mutex::Autolock _l(mLock);
Marco Nelissen465faa92010-02-26 13:16:23 -0800408 if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 return NO_ERROR;
410 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
411 status_t ret = mPlayer->pause();
412 if (ret != NO_ERROR) {
413 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
414 } else {
415 mCurrentState = MEDIA_PLAYER_PAUSED;
416 }
417 return ret;
418 }
419 LOGE("pause called in state %d", mCurrentState);
420 return INVALID_OPERATION;
421}
422
423bool MediaPlayer::isPlaying()
424{
425 Mutex::Autolock _l(mLock);
426 if (mPlayer != 0) {
427 bool temp = false;
428 mPlayer->isPlaying(&temp);
429 LOGV("isPlaying: %d", temp);
430 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
431 LOGE("internal/external state mismatch corrected");
432 mCurrentState = MEDIA_PLAYER_PAUSED;
433 }
434 return temp;
435 }
436 LOGV("isPlaying: no active player");
437 return false;
438}
439
440status_t MediaPlayer::getVideoWidth(int *w)
441{
442 LOGV("getVideoWidth");
443 Mutex::Autolock _l(mLock);
444 if (mPlayer == 0) return INVALID_OPERATION;
445 *w = mVideoWidth;
446 return NO_ERROR;
447}
448
449status_t MediaPlayer::getVideoHeight(int *h)
450{
451 LOGV("getVideoHeight");
452 Mutex::Autolock _l(mLock);
453 if (mPlayer == 0) return INVALID_OPERATION;
454 *h = mVideoHeight;
455 return NO_ERROR;
456}
457
458status_t MediaPlayer::getCurrentPosition(int *msec)
459{
460 LOGV("getCurrentPosition");
461 Mutex::Autolock _l(mLock);
462 if (mPlayer != 0) {
463 if (mCurrentPosition >= 0) {
464 LOGV("Using cached seek position: %d", mCurrentPosition);
465 *msec = mCurrentPosition;
466 return NO_ERROR;
467 }
468 return mPlayer->getCurrentPosition(msec);
469 }
470 return INVALID_OPERATION;
471}
472
473status_t MediaPlayer::getDuration_l(int *msec)
474{
475 LOGV("getDuration");
476 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
477 if (mPlayer != 0 && isValidState) {
478 status_t ret = NO_ERROR;
479 if (mDuration <= 0)
480 ret = mPlayer->getDuration(&mDuration);
481 if (msec)
482 *msec = mDuration;
483 return ret;
484 }
485 LOGE("Attempt to call getDuration without a valid mediaplayer");
486 return INVALID_OPERATION;
487}
488
489status_t MediaPlayer::getDuration(int *msec)
490{
491 Mutex::Autolock _l(mLock);
492 return getDuration_l(msec);
493}
494
495status_t MediaPlayer::seekTo_l(int msec)
496{
497 LOGV("seekTo %d", msec);
498 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
499 if ( msec < 0 ) {
500 LOGW("Attempt to seek to invalid position: %d", msec);
501 msec = 0;
502 } else if ((mDuration > 0) && (msec > mDuration)) {
503 LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
504 msec = mDuration;
505 }
506 // cache duration
507 mCurrentPosition = msec;
508 if (mSeekPosition < 0) {
509 getDuration_l(NULL);
510 mSeekPosition = msec;
511 return mPlayer->seekTo(msec);
512 }
513 else {
514 LOGV("Seek in progress - queue up seekTo[%d]", msec);
515 return NO_ERROR;
516 }
517 }
518 LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
519 return INVALID_OPERATION;
520}
521
522status_t MediaPlayer::seekTo(int msec)
523{
Andreas Hubereffd8d52009-03-24 20:48:51 -0700524 mLockThreadId = getThreadId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 Mutex::Autolock _l(mLock);
Andreas Hubereffd8d52009-03-24 20:48:51 -0700526 status_t result = seekTo_l(msec);
527 mLockThreadId = 0;
528
529 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530}
531
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700532status_t MediaPlayer::reset_l()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 mLoop = false;
535 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
536 mPrepareSync = false;
537 if (mPlayer != 0) {
538 status_t ret = mPlayer->reset();
539 if (ret != NO_ERROR) {
540 LOGE("reset() failed with return code (%d)", ret);
541 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
542 } else {
543 mCurrentState = MEDIA_PLAYER_IDLE;
544 }
James Dongc5bba6c2010-11-18 12:23:58 -0800545 // setDataSource has to be called again to create a
546 // new mediaplayer.
547 mPlayer = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 return ret;
549 }
550 clear_l();
551 return NO_ERROR;
552}
553
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700554status_t MediaPlayer::reset()
555{
556 LOGV("reset");
557 Mutex::Autolock _l(mLock);
558 return reset_l();
559}
560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561status_t MediaPlayer::setAudioStreamType(int type)
562{
563 LOGV("MediaPlayer::setAudioStreamType");
564 Mutex::Autolock _l(mLock);
565 if (mStreamType == type) return NO_ERROR;
566 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
567 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
568 // Can't change the stream type after prepare
569 LOGE("setAudioStream called in state %d", mCurrentState);
570 return INVALID_OPERATION;
571 }
572 // cache
573 mStreamType = type;
574 return OK;
575}
576
577status_t MediaPlayer::setLooping(int loop)
578{
579 LOGV("MediaPlayer::setLooping");
580 Mutex::Autolock _l(mLock);
581 mLoop = (loop != 0);
582 if (mPlayer != 0) {
583 return mPlayer->setLooping(loop);
584 }
585 return OK;
586}
587
588bool MediaPlayer::isLooping() {
589 LOGV("isLooping");
590 Mutex::Autolock _l(mLock);
591 if (mPlayer != 0) {
592 return mLoop;
593 }
594 LOGV("isLooping: no active player");
595 return false;
596}
597
598status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
599{
600 LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
601 Mutex::Autolock _l(mLock);
602 mLeftVolume = leftVolume;
603 mRightVolume = rightVolume;
604 if (mPlayer != 0) {
605 return mPlayer->setVolume(leftVolume, rightVolume);
606 }
607 return OK;
608}
609
Eric Laurent619346f2010-06-21 09:27:30 -0700610status_t MediaPlayer::setAudioSessionId(int sessionId)
611{
612 LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
613 Mutex::Autolock _l(mLock);
614 if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
615 LOGE("setAudioSessionId called in state %d", mCurrentState);
616 return INVALID_OPERATION;
617 }
618 if (sessionId < 0) {
619 return BAD_VALUE;
620 }
621 mAudioSessionId = sessionId;
622 return NO_ERROR;
623}
624
625int MediaPlayer::getAudioSessionId()
626{
627 Mutex::Autolock _l(mLock);
628 return mAudioSessionId;
629}
630
Eric Laurent7070b362010-07-16 07:43:46 -0700631status_t MediaPlayer::setAuxEffectSendLevel(float level)
632{
633 LOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
634 Mutex::Autolock _l(mLock);
635 mSendLevel = level;
636 if (mPlayer != 0) {
637 return mPlayer->setAuxEffectSendLevel(level);
638 }
639 return OK;
640}
641
642status_t MediaPlayer::attachAuxEffect(int effectId)
643{
644 LOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
645 Mutex::Autolock _l(mLock);
646 if (mPlayer == 0 ||
647 (mCurrentState & MEDIA_PLAYER_IDLE) ||
648 (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
649 LOGE("attachAuxEffect called in state %d", mCurrentState);
650 return INVALID_OPERATION;
651 }
652
653 return mPlayer->attachAuxEffect(effectId);
654}
655
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700656status_t MediaPlayer::setParameter(int key, const Parcel& request)
657{
658 LOGV("MediaPlayer::setParameter(%d)", key);
659 Mutex::Autolock _l(mLock);
660 if (mPlayer != NULL) {
661 return mPlayer->setParameter(key, request);
662 }
663 LOGV("setParameter: no active player");
664 return INVALID_OPERATION;
665}
666
667status_t MediaPlayer::getParameter(int key, Parcel *reply)
668{
669 LOGV("MediaPlayer::getParameter(%d)", key);
670 Mutex::Autolock _l(mLock);
671 if (mPlayer != NULL) {
672 return mPlayer->getParameter(key, reply);
673 }
674 LOGV("getParameter: no active player");
675 return INVALID_OPERATION;
676}
677
Gloria Wang162ee492011-04-11 17:23:27 -0700678void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679{
680 LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
681 bool send = true;
Jason Samsebb020a2009-03-24 18:45:22 -0700682 bool locked = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683
684 // TODO: In the future, we might be on the same thread if the app is
685 // running in the same process as the media server. In that case,
686 // this will deadlock.
Nicolas Catania32f82772009-06-11 16:33:49 -0700687 //
Jason Samsebb020a2009-03-24 18:45:22 -0700688 // The threadId hack below works around this for the care of prepare
Andreas Hubereffd8d52009-03-24 20:48:51 -0700689 // and seekTo within the same process.
690 // FIXME: Remember, this is a hack, it's not even a hack that is applied
691 // consistently for all use-cases, this needs to be revisited.
Jason Samsebb020a2009-03-24 18:45:22 -0700692 if (mLockThreadId != getThreadId()) {
693 mLock.lock();
694 locked = true;
Nicolas Catania32f82772009-06-11 16:33:49 -0700695 }
Jason Samsebb020a2009-03-24 18:45:22 -0700696
Eric Laurent1d53b2a2010-08-03 07:49:49 -0700697 // Allows calls from JNI in idle state to notify errors
698 if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Samsebb020a2009-03-24 18:45:22 -0700700 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 return;
702 }
703
704 switch (msg) {
705 case MEDIA_NOP: // interface test message
706 break;
707 case MEDIA_PREPARED:
708 LOGV("prepared");
709 mCurrentState = MEDIA_PLAYER_PREPARED;
710 if (mPrepareSync) {
711 LOGV("signal application thread");
712 mPrepareSync = false;
713 mPrepareStatus = NO_ERROR;
714 mSignal.signal();
715 }
716 break;
717 case MEDIA_PLAYBACK_COMPLETE:
718 LOGV("playback complete");
Marco Nelissen3c473ea2010-09-17 15:04:01 -0700719 if (mCurrentState == MEDIA_PLAYER_IDLE) {
720 LOGE("playback complete in idle state");
721 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 if (!mLoop) {
723 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
724 }
725 break;
726 case MEDIA_ERROR:
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700727 // Always log errors.
728 // ext1: Media framework error code.
729 // ext2: Implementation dependant error code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 LOGE("error (%d, %d)", ext1, ext2);
731 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
732 if (mPrepareSync)
733 {
734 LOGV("signal application thread");
735 mPrepareSync = false;
736 mPrepareStatus = ext1;
737 mSignal.signal();
738 send = false;
739 }
740 break;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700741 case MEDIA_INFO:
742 // ext1: Media framework error code.
743 // ext2: Implementation dependant error code.
Andreas Huber52c78322011-01-11 15:05:28 -0800744 if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
745 LOGW("info/warning (%d, %d)", ext1, ext2);
746 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700747 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 case MEDIA_SEEK_COMPLETE:
749 LOGV("Received seek complete");
750 if (mSeekPosition != mCurrentPosition) {
751 LOGV("Executing queued seekTo(%d)", mSeekPosition);
752 mSeekPosition = -1;
753 seekTo_l(mCurrentPosition);
754 }
755 else {
756 LOGV("All seeks complete - return to regularly scheduled program");
757 mCurrentPosition = mSeekPosition = -1;
758 }
759 break;
760 case MEDIA_BUFFERING_UPDATE:
761 LOGV("buffering %d", ext1);
762 break;
763 case MEDIA_SET_VIDEO_SIZE:
764 LOGV("New video size %d x %d", ext1, ext2);
765 mVideoWidth = ext1;
766 mVideoHeight = ext2;
767 break;
Gloria Wang162ee492011-04-11 17:23:27 -0700768 case MEDIA_TIMED_TEXT:
769 LOGV("Received timed text message");
770 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 default:
772 LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
773 break;
774 }
775
776 sp<MediaPlayerListener> listener = mListener;
Jason Samsebb020a2009-03-24 18:45:22 -0700777 if (locked) mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778
779 // this prevents re-entrant calls into client code
780 if ((listener != 0) && send) {
781 Mutex::Autolock _l(mNotifyLock);
782 LOGV("callback application");
Gloria Wang162ee492011-04-11 17:23:27 -0700783 listener->notify(msg, ext1, ext2, obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 LOGV("back from callback");
785 }
786}
787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
789{
790 LOGV("decode(%s)", url);
791 sp<IMemory> p;
792 const sp<IMediaPlayerService>& service = getMediaPlayerService();
793 if (service != 0) {
James Dong34bbc222010-01-15 18:13:58 -0800794 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 } else {
796 LOGE("Unable to locate media service");
797 }
798 return p;
799
800}
801
James Dong34bbc222010-01-15 18:13:58 -0800802void MediaPlayer::died()
803{
804 LOGV("died");
805 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
806}
807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
809{
810 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
811 sp<IMemory> p;
812 const sp<IMediaPlayerService>& service = getMediaPlayerService();
813 if (service != 0) {
James Dong34bbc222010-01-15 18:13:58 -0800814 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 } else {
816 LOGE("Unable to locate media service");
817 }
818 return p;
819
820}
821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822}; // namespace android