blob: 111962c33fcaa6c5d5bc9984957b9e7ceb17f71b [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();
Marco Nelissen3a34bef2011-08-02 13:33:41 -070064 AudioSystem::acquireAudioSessionId(mAudioSessionId);
Eric Laurent8c563ed2010-10-07 18:23:03 -070065 mSendLevel = 0;
John Grossman68f09452012-02-22 15:38:35 -080066 mRetransmitEndpointValid = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080067}
68
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080069MediaPlayer::~MediaPlayer()
70{
71 LOGV("destructor");
Marco Nelissen3a34bef2011-08-02 13:33:41 -070072 AudioSystem::releaseAudioSessionId(mAudioSessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080073 disconnect();
74 IPCThreadState::self()->flushCommands();
75}
76
77void MediaPlayer::disconnect()
78{
79 LOGV("disconnect");
80 sp<IMediaPlayer> p;
81 {
82 Mutex::Autolock _l(mLock);
83 p = mPlayer;
84 mPlayer.clear();
85 }
86
87 if (p != 0) {
88 p->disconnect();
89 }
90}
91
92// always call with lock held
93void MediaPlayer::clear_l()
94{
95 mDuration = -1;
96 mCurrentPosition = -1;
97 mSeekPosition = -1;
98 mVideoWidth = mVideoHeight = 0;
John Grossman68f09452012-02-22 15:38:35 -080099 mRetransmitEndpointValid = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800100}
101
102status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
103{
104 LOGV("setListener");
105 Mutex::Autolock _l(mLock);
106 mListener = listener;
107 return NO_ERROR;
108}
109
110
Dave Burked681bbb2011-08-30 14:39:17 +0100111status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800112{
113 status_t err = UNKNOWN_ERROR;
114 sp<IMediaPlayer> p;
115 { // scope for the lock
116 Mutex::Autolock _l(mLock);
117
Marco Nelissen83ff1432010-03-10 10:53:16 -0800118 if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
119 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
Dave Burked681bbb2011-08-30 14:39:17 +0100120 LOGE("attachNewPlayer called in state %d", mCurrentState);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800121 return INVALID_OPERATION;
122 }
123
124 clear_l();
125 p = mPlayer;
126 mPlayer = player;
127 if (player != 0) {
128 mCurrentState = MEDIA_PLAYER_INITIALIZED;
129 err = NO_ERROR;
130 } else {
131 LOGE("Unable to to create media player");
132 }
133 }
134
135 if (p != 0) {
136 p->disconnect();
137 }
138
139 return err;
140}
141
Andreas Huber2db84552010-01-28 11:19:57 -0800142status_t MediaPlayer::setDataSource(
143 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800144{
145 LOGV("setDataSource(%s)", url);
146 status_t err = BAD_VALUE;
147 if (url != NULL) {
148 const sp<IMediaPlayerService>& service(getMediaPlayerService());
149 if (service != 0) {
Dave Burked681bbb2011-08-30 14:39:17 +0100150 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
John Grossman68f09452012-02-22 15:38:35 -0800151 if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
152 (NO_ERROR != player->setDataSource(url, headers))) {
Dave Burke06620672011-09-06 20:39:47 +0100153 player.clear();
Dave Burked681bbb2011-08-30 14:39:17 +0100154 }
Dave Burke06620672011-09-06 20:39:47 +0100155 err = attachNewPlayer(player);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800156 }
157 }
158 return err;
159}
160
161status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
162{
163 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
164 status_t err = UNKNOWN_ERROR;
165 const sp<IMediaPlayerService>& service(getMediaPlayerService());
166 if (service != 0) {
Dave Burked681bbb2011-08-30 14:39:17 +0100167 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
John Grossman68f09452012-02-22 15:38:35 -0800168 if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
169 (NO_ERROR != player->setDataSource(fd, offset, length))) {
Dave Burke06620672011-09-06 20:39:47 +0100170 player.clear();
Dave Burked681bbb2011-08-30 14:39:17 +0100171 }
Dave Burke06620672011-09-06 20:39:47 +0100172 err = attachNewPlayer(player);
Dave Burked681bbb2011-08-30 14:39:17 +0100173 }
174 return err;
175}
176
177status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
178{
179 LOGV("setDataSource");
180 status_t err = UNKNOWN_ERROR;
181 const sp<IMediaPlayerService>& service(getMediaPlayerService());
182 if (service != 0) {
183 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
John Grossman68f09452012-02-22 15:38:35 -0800184 if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
185 (NO_ERROR != player->setDataSource(source))) {
Dave Burke06620672011-09-06 20:39:47 +0100186 player.clear();
Dave Burked681bbb2011-08-30 14:39:17 +0100187 }
Dave Burke06620672011-09-06 20:39:47 +0100188 err = attachNewPlayer(player);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800189 }
190 return err;
191}
192
Nicolas Catania1d187f12009-05-12 23:25:55 -0700193status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
194{
195 Mutex::Autolock _l(mLock);
Nicolas Catania40234932010-03-10 10:41:04 -0800196 const bool hasBeenInitialized =
197 (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
198 ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
199 if ((mPlayer != NULL) && hasBeenInitialized) {
Nicolas Catania1d187f12009-05-12 23:25:55 -0700200 LOGV("invoke %d", request.dataSize());
201 return mPlayer->invoke(request, reply);
202 }
203 LOGE("invoke failed: wrong state %X", mCurrentState);
204 return INVALID_OPERATION;
205}
206
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700207status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
208{
209 LOGD("setMetadataFilter");
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700210 Mutex::Autolock lock(mLock);
211 if (mPlayer == NULL) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700212 return NO_INIT;
213 }
214 return mPlayer->setMetadataFilter(filter);
215}
Nicolas Catania1d187f12009-05-12 23:25:55 -0700216
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700217status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
218{
219 LOGD("getMetadata");
220 Mutex::Autolock lock(mLock);
221 if (mPlayer == NULL) {
222 return NO_INIT;
223 }
224 return mPlayer->getMetadata(update_only, apply_filter, metadata);
225}
226
Glenn Kasten11731182011-02-08 17:26:17 -0800227status_t MediaPlayer::setVideoSurfaceTexture(
228 const sp<ISurfaceTexture>& surfaceTexture)
229{
230 LOGV("setVideoSurfaceTexture");
231 Mutex::Autolock _l(mLock);
232 if (mPlayer == 0) return NO_INIT;
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700233 return mPlayer->setVideoSurfaceTexture(surfaceTexture);
Glenn Kasten11731182011-02-08 17:26:17 -0800234}
235
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800236// must call with lock held
237status_t MediaPlayer::prepareAsync_l()
238{
239 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
240 mPlayer->setAudioStreamType(mStreamType);
241 mCurrentState = MEDIA_PLAYER_PREPARING;
242 return mPlayer->prepareAsync();
243 }
244 LOGE("prepareAsync called in state %d", mCurrentState);
245 return INVALID_OPERATION;
246}
247
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700248// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
249// one defined in the Android framework and one provided by the implementation
250// that generated the error. The sync version of prepare returns only 1 error
251// code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800252status_t MediaPlayer::prepare()
253{
254 LOGV("prepare");
255 Mutex::Autolock _l(mLock);
Jason Sams1af452f2009-03-24 18:45:22 -0700256 mLockThreadId = getThreadId();
257 if (mPrepareSync) {
258 mLockThreadId = 0;
259 return -EALREADY;
260 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800261 mPrepareSync = true;
262 status_t ret = prepareAsync_l();
Jason Sams1af452f2009-03-24 18:45:22 -0700263 if (ret != NO_ERROR) {
264 mLockThreadId = 0;
265 return ret;
266 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800267
268 if (mPrepareSync) {
269 mSignal.wait(mLock); // wait for prepare done
270 mPrepareSync = false;
271 }
272 LOGV("prepare complete - status=%d", mPrepareStatus);
Jason Sams1af452f2009-03-24 18:45:22 -0700273 mLockThreadId = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800274 return mPrepareStatus;
275}
276
277status_t MediaPlayer::prepareAsync()
278{
279 LOGV("prepareAsync");
280 Mutex::Autolock _l(mLock);
281 return prepareAsync_l();
282}
283
284status_t MediaPlayer::start()
285{
286 LOGV("start");
287 Mutex::Autolock _l(mLock);
288 if (mCurrentState & MEDIA_PLAYER_STARTED)
289 return NO_ERROR;
290 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
291 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
292 mPlayer->setLooping(mLoop);
293 mPlayer->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -0700294 mPlayer->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800295 mCurrentState = MEDIA_PLAYER_STARTED;
296 status_t ret = mPlayer->start();
297 if (ret != NO_ERROR) {
298 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
299 } else {
300 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
301 LOGV("playback completed immediately following start()");
302 }
303 }
304 return ret;
305 }
306 LOGE("start called in state %d", mCurrentState);
307 return INVALID_OPERATION;
308}
309
310status_t MediaPlayer::stop()
311{
312 LOGV("stop");
313 Mutex::Autolock _l(mLock);
314 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
315 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
316 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
317 status_t ret = mPlayer->stop();
318 if (ret != NO_ERROR) {
319 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
320 } else {
321 mCurrentState = MEDIA_PLAYER_STOPPED;
322 }
323 return ret;
324 }
325 LOGE("stop called in state %d", mCurrentState);
326 return INVALID_OPERATION;
327}
328
329status_t MediaPlayer::pause()
330{
331 LOGV("pause");
332 Mutex::Autolock _l(mLock);
Marco Nelissen698f4762010-02-26 13:16:23 -0800333 if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800334 return NO_ERROR;
335 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
336 status_t ret = mPlayer->pause();
337 if (ret != NO_ERROR) {
338 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
339 } else {
340 mCurrentState = MEDIA_PLAYER_PAUSED;
341 }
342 return ret;
343 }
344 LOGE("pause called in state %d", mCurrentState);
345 return INVALID_OPERATION;
346}
347
348bool MediaPlayer::isPlaying()
349{
350 Mutex::Autolock _l(mLock);
351 if (mPlayer != 0) {
352 bool temp = false;
353 mPlayer->isPlaying(&temp);
354 LOGV("isPlaying: %d", temp);
355 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
356 LOGE("internal/external state mismatch corrected");
357 mCurrentState = MEDIA_PLAYER_PAUSED;
358 }
359 return temp;
360 }
361 LOGV("isPlaying: no active player");
362 return false;
363}
364
365status_t MediaPlayer::getVideoWidth(int *w)
366{
367 LOGV("getVideoWidth");
368 Mutex::Autolock _l(mLock);
369 if (mPlayer == 0) return INVALID_OPERATION;
370 *w = mVideoWidth;
371 return NO_ERROR;
372}
373
374status_t MediaPlayer::getVideoHeight(int *h)
375{
376 LOGV("getVideoHeight");
377 Mutex::Autolock _l(mLock);
378 if (mPlayer == 0) return INVALID_OPERATION;
379 *h = mVideoHeight;
380 return NO_ERROR;
381}
382
383status_t MediaPlayer::getCurrentPosition(int *msec)
384{
385 LOGV("getCurrentPosition");
386 Mutex::Autolock _l(mLock);
387 if (mPlayer != 0) {
388 if (mCurrentPosition >= 0) {
389 LOGV("Using cached seek position: %d", mCurrentPosition);
390 *msec = mCurrentPosition;
391 return NO_ERROR;
392 }
393 return mPlayer->getCurrentPosition(msec);
394 }
395 return INVALID_OPERATION;
396}
397
398status_t MediaPlayer::getDuration_l(int *msec)
399{
400 LOGV("getDuration");
401 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
402 if (mPlayer != 0 && isValidState) {
403 status_t ret = NO_ERROR;
404 if (mDuration <= 0)
405 ret = mPlayer->getDuration(&mDuration);
406 if (msec)
407 *msec = mDuration;
408 return ret;
409 }
410 LOGE("Attempt to call getDuration without a valid mediaplayer");
411 return INVALID_OPERATION;
412}
413
414status_t MediaPlayer::getDuration(int *msec)
415{
416 Mutex::Autolock _l(mLock);
417 return getDuration_l(msec);
418}
419
420status_t MediaPlayer::seekTo_l(int msec)
421{
422 LOGV("seekTo %d", msec);
423 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
424 if ( msec < 0 ) {
425 LOGW("Attempt to seek to invalid position: %d", msec);
426 msec = 0;
427 } else if ((mDuration > 0) && (msec > mDuration)) {
428 LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
429 msec = mDuration;
430 }
431 // cache duration
432 mCurrentPosition = msec;
433 if (mSeekPosition < 0) {
434 getDuration_l(NULL);
435 mSeekPosition = msec;
436 return mPlayer->seekTo(msec);
437 }
438 else {
439 LOGV("Seek in progress - queue up seekTo[%d]", msec);
440 return NO_ERROR;
441 }
442 }
443 LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
444 return INVALID_OPERATION;
445}
446
447status_t MediaPlayer::seekTo(int msec)
448{
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700449 mLockThreadId = getThreadId();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800450 Mutex::Autolock _l(mLock);
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700451 status_t result = seekTo_l(msec);
452 mLockThreadId = 0;
453
454 return result;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800455}
456
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700457status_t MediaPlayer::reset_l()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800458{
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800459 mLoop = false;
460 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
461 mPrepareSync = false;
462 if (mPlayer != 0) {
463 status_t ret = mPlayer->reset();
464 if (ret != NO_ERROR) {
465 LOGE("reset() failed with return code (%d)", ret);
466 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
467 } else {
468 mCurrentState = MEDIA_PLAYER_IDLE;
469 }
James Donga1680bc2010-11-18 12:23:58 -0800470 // setDataSource has to be called again to create a
471 // new mediaplayer.
472 mPlayer = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800473 return ret;
474 }
475 clear_l();
476 return NO_ERROR;
477}
478
John Grossman68f09452012-02-22 15:38:35 -0800479status_t MediaPlayer::doSetRetransmitEndpoint(const sp<IMediaPlayer>& player) {
480 Mutex::Autolock _l(mLock);
481
482 if (player == NULL)
483 return UNKNOWN_ERROR;
484
485 if (mRetransmitEndpointValid)
486 return player->setRetransmitEndpoint(&mRetransmitEndpoint);
487
488 return OK;
489}
490
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700491status_t MediaPlayer::reset()
492{
493 LOGV("reset");
494 Mutex::Autolock _l(mLock);
495 return reset_l();
496}
497
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800498status_t MediaPlayer::setAudioStreamType(int type)
499{
500 LOGV("MediaPlayer::setAudioStreamType");
501 Mutex::Autolock _l(mLock);
502 if (mStreamType == type) return NO_ERROR;
503 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
504 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
505 // Can't change the stream type after prepare
506 LOGE("setAudioStream called in state %d", mCurrentState);
507 return INVALID_OPERATION;
508 }
509 // cache
510 mStreamType = type;
511 return OK;
512}
513
514status_t MediaPlayer::setLooping(int loop)
515{
516 LOGV("MediaPlayer::setLooping");
517 Mutex::Autolock _l(mLock);
518 mLoop = (loop != 0);
519 if (mPlayer != 0) {
520 return mPlayer->setLooping(loop);
521 }
522 return OK;
523}
524
525bool MediaPlayer::isLooping() {
526 LOGV("isLooping");
527 Mutex::Autolock _l(mLock);
528 if (mPlayer != 0) {
529 return mLoop;
530 }
531 LOGV("isLooping: no active player");
532 return false;
533}
534
535status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
536{
537 LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
538 Mutex::Autolock _l(mLock);
539 mLeftVolume = leftVolume;
540 mRightVolume = rightVolume;
541 if (mPlayer != 0) {
542 return mPlayer->setVolume(leftVolume, rightVolume);
543 }
544 return OK;
545}
546
Eric Laurenta514bdb2010-06-21 09:27:30 -0700547status_t MediaPlayer::setAudioSessionId(int sessionId)
548{
549 LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
550 Mutex::Autolock _l(mLock);
551 if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
552 LOGE("setAudioSessionId called in state %d", mCurrentState);
553 return INVALID_OPERATION;
554 }
555 if (sessionId < 0) {
556 return BAD_VALUE;
557 }
Marco Nelissen3a34bef2011-08-02 13:33:41 -0700558 if (sessionId != mAudioSessionId) {
559 AudioSystem::releaseAudioSessionId(mAudioSessionId);
560 AudioSystem::acquireAudioSessionId(sessionId);
561 mAudioSessionId = sessionId;
562 }
Eric Laurenta514bdb2010-06-21 09:27:30 -0700563 return NO_ERROR;
564}
565
566int MediaPlayer::getAudioSessionId()
567{
568 Mutex::Autolock _l(mLock);
569 return mAudioSessionId;
570}
571
Eric Laurent2beeb502010-07-16 07:43:46 -0700572status_t MediaPlayer::setAuxEffectSendLevel(float level)
573{
574 LOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
575 Mutex::Autolock _l(mLock);
576 mSendLevel = level;
577 if (mPlayer != 0) {
578 return mPlayer->setAuxEffectSendLevel(level);
579 }
580 return OK;
581}
582
583status_t MediaPlayer::attachAuxEffect(int effectId)
584{
585 LOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
586 Mutex::Autolock _l(mLock);
587 if (mPlayer == 0 ||
588 (mCurrentState & MEDIA_PLAYER_IDLE) ||
589 (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
590 LOGE("attachAuxEffect called in state %d", mCurrentState);
591 return INVALID_OPERATION;
592 }
593
594 return mPlayer->attachAuxEffect(effectId);
595}
596
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700597status_t MediaPlayer::setParameter(int key, const Parcel& request)
598{
599 LOGV("MediaPlayer::setParameter(%d)", key);
600 Mutex::Autolock _l(mLock);
601 if (mPlayer != NULL) {
602 return mPlayer->setParameter(key, request);
603 }
604 LOGV("setParameter: no active player");
605 return INVALID_OPERATION;
606}
607
608status_t MediaPlayer::getParameter(int key, Parcel *reply)
609{
610 LOGV("MediaPlayer::getParameter(%d)", key);
611 Mutex::Autolock _l(mLock);
612 if (mPlayer != NULL) {
613 return mPlayer->getParameter(key, reply);
614 }
615 LOGV("getParameter: no active player");
616 return INVALID_OPERATION;
617}
618
John Grossman68f09452012-02-22 15:38:35 -0800619status_t MediaPlayer::setRetransmitEndpoint(const char* addrString,
620 uint16_t port) {
621 LOGV("MediaPlayer::setRetransmitEndpoint(%s:%hu)",
622 addrString ? addrString : "(null)", port);
623
624 Mutex::Autolock _l(mLock);
625 if ((mPlayer == NULL) && (mCurrentState == MEDIA_PLAYER_IDLE)) {
626 if (NULL == addrString) {
627 mRetransmitEndpointValid = false;
628 return OK;
629 }
630
631 struct in_addr saddr;
632 if(!inet_aton(addrString, &saddr)) {
633 return BAD_VALUE;
634 }
635
636 memset(&mRetransmitEndpoint, 0, sizeof(&mRetransmitEndpoint));
637 mRetransmitEndpoint.sin_family = AF_INET;
638 mRetransmitEndpoint.sin_addr = saddr;
639 mRetransmitEndpoint.sin_port = htons(port);
640 mRetransmitEndpointValid = true;
641
642 return OK;
643 }
644
645 LOGV("setRetransmitEndpoint: after idle");
646 return INVALID_OPERATION;
647}
648
Gloria Wangb483c472011-04-11 17:23:27 -0700649void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800650{
651 LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
652 bool send = true;
Jason Sams1af452f2009-03-24 18:45:22 -0700653 bool locked = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800654
655 // TODO: In the future, we might be on the same thread if the app is
656 // running in the same process as the media server. In that case,
657 // this will deadlock.
Nicolas Catania66095182009-06-11 16:33:49 -0700658 //
Jason Sams1af452f2009-03-24 18:45:22 -0700659 // The threadId hack below works around this for the care of prepare
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700660 // and seekTo within the same process.
661 // FIXME: Remember, this is a hack, it's not even a hack that is applied
662 // consistently for all use-cases, this needs to be revisited.
Jason Sams1af452f2009-03-24 18:45:22 -0700663 if (mLockThreadId != getThreadId()) {
664 mLock.lock();
665 locked = true;
Nicolas Catania66095182009-06-11 16:33:49 -0700666 }
Jason Sams1af452f2009-03-24 18:45:22 -0700667
Eric Laurent3b268442010-08-03 07:49:49 -0700668 // Allows calls from JNI in idle state to notify errors
669 if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800670 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Sams1af452f2009-03-24 18:45:22 -0700671 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800672 return;
673 }
674
675 switch (msg) {
676 case MEDIA_NOP: // interface test message
677 break;
678 case MEDIA_PREPARED:
679 LOGV("prepared");
680 mCurrentState = MEDIA_PLAYER_PREPARED;
681 if (mPrepareSync) {
682 LOGV("signal application thread");
683 mPrepareSync = false;
684 mPrepareStatus = NO_ERROR;
685 mSignal.signal();
686 }
687 break;
688 case MEDIA_PLAYBACK_COMPLETE:
689 LOGV("playback complete");
Marco Nelissen1c1503c2010-09-17 15:04:01 -0700690 if (mCurrentState == MEDIA_PLAYER_IDLE) {
691 LOGE("playback complete in idle state");
692 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800693 if (!mLoop) {
694 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
695 }
696 break;
697 case MEDIA_ERROR:
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700698 // Always log errors.
699 // ext1: Media framework error code.
700 // ext2: Implementation dependant error code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800701 LOGE("error (%d, %d)", ext1, ext2);
702 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
703 if (mPrepareSync)
704 {
705 LOGV("signal application thread");
706 mPrepareSync = false;
707 mPrepareStatus = ext1;
708 mSignal.signal();
709 send = false;
710 }
711 break;
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700712 case MEDIA_INFO:
713 // ext1: Media framework error code.
714 // ext2: Implementation dependant error code.
Andreas Huber145e68f2011-01-11 15:05:28 -0800715 if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
716 LOGW("info/warning (%d, %d)", ext1, ext2);
717 }
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700718 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800719 case MEDIA_SEEK_COMPLETE:
720 LOGV("Received seek complete");
721 if (mSeekPosition != mCurrentPosition) {
722 LOGV("Executing queued seekTo(%d)", mSeekPosition);
723 mSeekPosition = -1;
724 seekTo_l(mCurrentPosition);
725 }
726 else {
727 LOGV("All seeks complete - return to regularly scheduled program");
728 mCurrentPosition = mSeekPosition = -1;
729 }
730 break;
731 case MEDIA_BUFFERING_UPDATE:
732 LOGV("buffering %d", ext1);
733 break;
734 case MEDIA_SET_VIDEO_SIZE:
735 LOGV("New video size %d x %d", ext1, ext2);
736 mVideoWidth = ext1;
737 mVideoHeight = ext2;
738 break;
Gloria Wangb483c472011-04-11 17:23:27 -0700739 case MEDIA_TIMED_TEXT:
740 LOGV("Received timed text message");
741 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800742 default:
743 LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
744 break;
745 }
746
747 sp<MediaPlayerListener> listener = mListener;
Jason Sams1af452f2009-03-24 18:45:22 -0700748 if (locked) mLock.unlock();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800749
750 // this prevents re-entrant calls into client code
751 if ((listener != 0) && send) {
752 Mutex::Autolock _l(mNotifyLock);
753 LOGV("callback application");
Gloria Wangb483c472011-04-11 17:23:27 -0700754 listener->notify(msg, ext1, ext2, obj);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800755 LOGV("back from callback");
756 }
757}
758
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800759/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
760{
761 LOGV("decode(%s)", url);
762 sp<IMemory> p;
763 const sp<IMediaPlayerService>& service = getMediaPlayerService();
764 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800765 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800766 } else {
767 LOGE("Unable to locate media service");
768 }
769 return p;
770
771}
772
James Dongdd172fc2010-01-15 18:13:58 -0800773void MediaPlayer::died()
774{
775 LOGV("died");
776 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
777}
778
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800779/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
780{
781 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
782 sp<IMemory> p;
783 const sp<IMediaPlayerService>& service = getMediaPlayerService();
784 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800785 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800786 } else {
787 LOGE("Unable to locate media service");
788 }
789 return p;
790
791}
792
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800793}; // namespace android