blob: 7ea94903cdeb9875a17756dd5bceb6f9e9fccc16 [file] [log] [blame]
Glenn Kastenb3db2132012-01-19 08:59:58 -08001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002**
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>
Glenn Kastena6dafea2012-01-18 14:54:46 -080033#include <media/AudioSystem.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
Mathias Agopian07952722009-05-19 19:08:10 -070035#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
Andreas Huber25643002010-01-28 11:19:57 -080037#include <utils/KeyedVector.h>
38#include <utils/String8.h>
39
Dima Zavin34bb4192011-05-11 14:15:23 -070040#include <system/audio.h>
Jamie Gennisc85ca5d2011-07-13 12:59:34 -070041#include <system/window.h>
Dima Zavin24fc2fb2011-04-19 22:30:36 -070042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043namespace android {
44
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045MediaPlayer::MediaPlayer()
46{
Steve Block71f2cf12011-10-20 11:56:00 +010047 ALOGV("constructor");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048 mListener = NULL;
49 mCookie = NULL;
50 mDuration = -1;
Dima Zavin24fc2fb2011-04-19 22:30:36 -070051 mStreamType = AUDIO_STREAM_MUSIC;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 mCurrentPosition = -1;
53 mSeekPosition = -1;
54 mCurrentState = MEDIA_PLAYER_IDLE;
55 mPrepareSync = false;
56 mPrepareStatus = NO_ERROR;
57 mLoop = false;
58 mLeftVolume = mRightVolume = 1.0;
59 mVideoWidth = mVideoHeight = 0;
Jason Samsebb020a2009-03-24 18:45:22 -070060 mLockThreadId = 0;
Eric Laurent619346f2010-06-21 09:27:30 -070061 mAudioSessionId = AudioSystem::newAudioSessionId();
Marco Nelissenc74b93f2011-08-02 13:33:41 -070062 AudioSystem::acquireAudioSessionId(mAudioSessionId);
Eric Laurentb3bdf3f2010-10-07 18:23:03 -070063 mSendLevel = 0;
John Grossman720aa282012-02-22 15:38:35 -080064 mRetransmitEndpointValid = false;
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{
Steve Block71f2cf12011-10-20 11:56:00 +010069 ALOGV("destructor");
Marco Nelissenc74b93f2011-08-02 13:33:41 -070070 AudioSystem::releaseAudioSessionId(mAudioSessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 disconnect();
72 IPCThreadState::self()->flushCommands();
73}
74
75void MediaPlayer::disconnect()
76{
Steve Block71f2cf12011-10-20 11:56:00 +010077 ALOGV("disconnect");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 sp<IMediaPlayer> p;
79 {
80 Mutex::Autolock _l(mLock);
81 p = mPlayer;
82 mPlayer.clear();
83 }
84
85 if (p != 0) {
86 p->disconnect();
87 }
88}
89
90// always call with lock held
91void MediaPlayer::clear_l()
92{
93 mDuration = -1;
94 mCurrentPosition = -1;
95 mSeekPosition = -1;
96 mVideoWidth = mVideoHeight = 0;
John Grossman720aa282012-02-22 15:38:35 -080097 mRetransmitEndpointValid = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098}
99
100status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
101{
Steve Block71f2cf12011-10-20 11:56:00 +0100102 ALOGV("setListener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 Mutex::Autolock _l(mLock);
104 mListener = listener;
105 return NO_ERROR;
106}
107
108
Dave Burkefc301b02011-08-30 14:39:17 +0100109status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110{
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 ) ) ) {
Steve Block3762c312012-01-06 19:20:56 +0000118 ALOGE("attachNewPlayer called in state %d", mCurrentState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 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 {
Steve Block3762c312012-01-06 19:20:56 +0000129 ALOGE("Unable to to create media player");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 }
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{
Steve Block71f2cf12011-10-20 11:56:00 +0100143 ALOGV("setDataSource(%s)", url);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 status_t err = BAD_VALUE;
145 if (url != NULL) {
146 const sp<IMediaPlayerService>& service(getMediaPlayerService());
147 if (service != 0) {
Dave Burkefc301b02011-08-30 14:39:17 +0100148 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
John Grossman720aa282012-02-22 15:38:35 -0800149 if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
150 (NO_ERROR != player->setDataSource(url, headers))) {
Dave Burkea28279b2011-09-06 20:39:47 +0100151 player.clear();
Dave Burkefc301b02011-08-30 14:39:17 +0100152 }
Dave Burkea28279b2011-09-06 20:39:47 +0100153 err = attachNewPlayer(player);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 }
155 }
156 return err;
157}
158
159status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
160{
Steve Block71f2cf12011-10-20 11:56:00 +0100161 ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 status_t err = UNKNOWN_ERROR;
163 const sp<IMediaPlayerService>& service(getMediaPlayerService());
164 if (service != 0) {
Dave Burkefc301b02011-08-30 14:39:17 +0100165 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
John Grossman720aa282012-02-22 15:38:35 -0800166 if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
167 (NO_ERROR != player->setDataSource(fd, offset, length))) {
Dave Burkea28279b2011-09-06 20:39:47 +0100168 player.clear();
Dave Burkefc301b02011-08-30 14:39:17 +0100169 }
Dave Burkea28279b2011-09-06 20:39:47 +0100170 err = attachNewPlayer(player);
Dave Burkefc301b02011-08-30 14:39:17 +0100171 }
172 return err;
173}
174
175status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
176{
Steve Block71f2cf12011-10-20 11:56:00 +0100177 ALOGV("setDataSource");
Dave Burkefc301b02011-08-30 14:39:17 +0100178 status_t err = UNKNOWN_ERROR;
179 const sp<IMediaPlayerService>& service(getMediaPlayerService());
180 if (service != 0) {
181 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
John Grossman720aa282012-02-22 15:38:35 -0800182 if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
183 (NO_ERROR != player->setDataSource(source))) {
Dave Burkea28279b2011-09-06 20:39:47 +0100184 player.clear();
Dave Burkefc301b02011-08-30 14:39:17 +0100185 }
Dave Burkea28279b2011-09-06 20:39:47 +0100186 err = attachNewPlayer(player);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 }
188 return err;
189}
190
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700191status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
192{
193 Mutex::Autolock _l(mLock);
Nicolas Catania7bd3d7d2010-03-10 10:41:04 -0800194 const bool hasBeenInitialized =
195 (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
196 ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
197 if ((mPlayer != NULL) && hasBeenInitialized) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700198 ALOGV("invoke %d", request.dataSize());
199 return mPlayer->invoke(request, reply);
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700200 }
Steve Block3762c312012-01-06 19:20:56 +0000201 ALOGE("invoke failed: wrong state %X", mCurrentState);
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700202 return INVALID_OPERATION;
203}
204
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700205status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
206{
Steve Block5baa3a62011-12-20 16:23:08 +0000207 ALOGD("setMetadataFilter");
Nicolas Catania5d55c712009-07-09 09:21:33 -0700208 Mutex::Autolock lock(mLock);
209 if (mPlayer == NULL) {
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700210 return NO_INIT;
211 }
212 return mPlayer->setMetadataFilter(filter);
213}
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700214
Nicolas Catania5d55c712009-07-09 09:21:33 -0700215status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
216{
Steve Block5baa3a62011-12-20 16:23:08 +0000217 ALOGD("getMetadata");
Nicolas Catania5d55c712009-07-09 09:21:33 -0700218 Mutex::Autolock lock(mLock);
219 if (mPlayer == NULL) {
220 return NO_INIT;
221 }
222 return mPlayer->getMetadata(update_only, apply_filter, metadata);
223}
224
Glenn Kastencc562a32011-02-08 17:26:17 -0800225status_t MediaPlayer::setVideoSurfaceTexture(
226 const sp<ISurfaceTexture>& surfaceTexture)
227{
Steve Block71f2cf12011-10-20 11:56:00 +0100228 ALOGV("setVideoSurfaceTexture");
Glenn Kastencc562a32011-02-08 17:26:17 -0800229 Mutex::Autolock _l(mLock);
230 if (mPlayer == 0) return NO_INIT;
Jamie Gennis2fa0ac22011-10-26 18:36:31 -0700231 return mPlayer->setVideoSurfaceTexture(surfaceTexture);
Glenn Kastencc562a32011-02-08 17:26:17 -0800232}
233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234// must call with lock held
235status_t MediaPlayer::prepareAsync_l()
236{
237 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
238 mPlayer->setAudioStreamType(mStreamType);
239 mCurrentState = MEDIA_PLAYER_PREPARING;
240 return mPlayer->prepareAsync();
241 }
Steve Block3762c312012-01-06 19:20:56 +0000242 ALOGE("prepareAsync called in state %d", mCurrentState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 return INVALID_OPERATION;
244}
245
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700246// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
247// one defined in the Android framework and one provided by the implementation
248// that generated the error. The sync version of prepare returns only 1 error
249// code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250status_t MediaPlayer::prepare()
251{
Steve Block71f2cf12011-10-20 11:56:00 +0100252 ALOGV("prepare");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 Mutex::Autolock _l(mLock);
Jason Samsebb020a2009-03-24 18:45:22 -0700254 mLockThreadId = getThreadId();
255 if (mPrepareSync) {
256 mLockThreadId = 0;
257 return -EALREADY;
258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 mPrepareSync = true;
260 status_t ret = prepareAsync_l();
Jason Samsebb020a2009-03-24 18:45:22 -0700261 if (ret != NO_ERROR) {
262 mLockThreadId = 0;
263 return ret;
264 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265
266 if (mPrepareSync) {
267 mSignal.wait(mLock); // wait for prepare done
268 mPrepareSync = false;
269 }
Steve Block71f2cf12011-10-20 11:56:00 +0100270 ALOGV("prepare complete - status=%d", mPrepareStatus);
Jason Samsebb020a2009-03-24 18:45:22 -0700271 mLockThreadId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 return mPrepareStatus;
273}
274
275status_t MediaPlayer::prepareAsync()
276{
Steve Block71f2cf12011-10-20 11:56:00 +0100277 ALOGV("prepareAsync");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 Mutex::Autolock _l(mLock);
279 return prepareAsync_l();
280}
281
282status_t MediaPlayer::start()
283{
Steve Block71f2cf12011-10-20 11:56:00 +0100284 ALOGV("start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 Mutex::Autolock _l(mLock);
286 if (mCurrentState & MEDIA_PLAYER_STARTED)
287 return NO_ERROR;
288 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
289 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
290 mPlayer->setLooping(mLoop);
291 mPlayer->setVolume(mLeftVolume, mRightVolume);
Eric Laurent7070b362010-07-16 07:43:46 -0700292 mPlayer->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 mCurrentState = MEDIA_PLAYER_STARTED;
294 status_t ret = mPlayer->start();
295 if (ret != NO_ERROR) {
296 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
297 } else {
298 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
Steve Block71f2cf12011-10-20 11:56:00 +0100299 ALOGV("playback completed immediately following start()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 }
301 }
302 return ret;
303 }
Steve Block3762c312012-01-06 19:20:56 +0000304 ALOGE("start called in state %d", mCurrentState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 return INVALID_OPERATION;
306}
307
308status_t MediaPlayer::stop()
309{
Steve Block71f2cf12011-10-20 11:56:00 +0100310 ALOGV("stop");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 Mutex::Autolock _l(mLock);
312 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
313 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
314 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
315 status_t ret = mPlayer->stop();
316 if (ret != NO_ERROR) {
317 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
318 } else {
319 mCurrentState = MEDIA_PLAYER_STOPPED;
320 }
321 return ret;
322 }
Steve Block3762c312012-01-06 19:20:56 +0000323 ALOGE("stop called in state %d", mCurrentState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 return INVALID_OPERATION;
325}
326
327status_t MediaPlayer::pause()
328{
Steve Block71f2cf12011-10-20 11:56:00 +0100329 ALOGV("pause");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 Mutex::Autolock _l(mLock);
Marco Nelissen465faa92010-02-26 13:16:23 -0800331 if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 return NO_ERROR;
333 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
334 status_t ret = mPlayer->pause();
335 if (ret != NO_ERROR) {
336 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
337 } else {
338 mCurrentState = MEDIA_PLAYER_PAUSED;
339 }
340 return ret;
341 }
Steve Block3762c312012-01-06 19:20:56 +0000342 ALOGE("pause called in state %d", mCurrentState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 return INVALID_OPERATION;
344}
345
346bool MediaPlayer::isPlaying()
347{
348 Mutex::Autolock _l(mLock);
349 if (mPlayer != 0) {
350 bool temp = false;
351 mPlayer->isPlaying(&temp);
Steve Block71f2cf12011-10-20 11:56:00 +0100352 ALOGV("isPlaying: %d", temp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
Steve Block3762c312012-01-06 19:20:56 +0000354 ALOGE("internal/external state mismatch corrected");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 mCurrentState = MEDIA_PLAYER_PAUSED;
356 }
357 return temp;
358 }
Steve Block71f2cf12011-10-20 11:56:00 +0100359 ALOGV("isPlaying: no active player");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 return false;
361}
362
363status_t MediaPlayer::getVideoWidth(int *w)
364{
Steve Block71f2cf12011-10-20 11:56:00 +0100365 ALOGV("getVideoWidth");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 Mutex::Autolock _l(mLock);
367 if (mPlayer == 0) return INVALID_OPERATION;
368 *w = mVideoWidth;
369 return NO_ERROR;
370}
371
372status_t MediaPlayer::getVideoHeight(int *h)
373{
Steve Block71f2cf12011-10-20 11:56:00 +0100374 ALOGV("getVideoHeight");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 Mutex::Autolock _l(mLock);
376 if (mPlayer == 0) return INVALID_OPERATION;
377 *h = mVideoHeight;
378 return NO_ERROR;
379}
380
381status_t MediaPlayer::getCurrentPosition(int *msec)
382{
Steve Block71f2cf12011-10-20 11:56:00 +0100383 ALOGV("getCurrentPosition");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 Mutex::Autolock _l(mLock);
385 if (mPlayer != 0) {
386 if (mCurrentPosition >= 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100387 ALOGV("Using cached seek position: %d", mCurrentPosition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 *msec = mCurrentPosition;
389 return NO_ERROR;
390 }
391 return mPlayer->getCurrentPosition(msec);
392 }
393 return INVALID_OPERATION;
394}
395
396status_t MediaPlayer::getDuration_l(int *msec)
397{
Steve Block71f2cf12011-10-20 11:56:00 +0100398 ALOGV("getDuration");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
400 if (mPlayer != 0 && isValidState) {
401 status_t ret = NO_ERROR;
402 if (mDuration <= 0)
403 ret = mPlayer->getDuration(&mDuration);
404 if (msec)
405 *msec = mDuration;
406 return ret;
407 }
Steve Block3762c312012-01-06 19:20:56 +0000408 ALOGE("Attempt to call getDuration without a valid mediaplayer");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 return INVALID_OPERATION;
410}
411
412status_t MediaPlayer::getDuration(int *msec)
413{
414 Mutex::Autolock _l(mLock);
415 return getDuration_l(msec);
416}
417
418status_t MediaPlayer::seekTo_l(int msec)
419{
Steve Block71f2cf12011-10-20 11:56:00 +0100420 ALOGV("seekTo %d", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
422 if ( msec < 0 ) {
Steve Block8564c8d2012-01-05 23:22:43 +0000423 ALOGW("Attempt to seek to invalid position: %d", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 msec = 0;
425 } else if ((mDuration > 0) && (msec > mDuration)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000426 ALOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 msec = mDuration;
428 }
429 // cache duration
430 mCurrentPosition = msec;
431 if (mSeekPosition < 0) {
432 getDuration_l(NULL);
433 mSeekPosition = msec;
434 return mPlayer->seekTo(msec);
435 }
436 else {
Steve Block71f2cf12011-10-20 11:56:00 +0100437 ALOGV("Seek in progress - queue up seekTo[%d]", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 return NO_ERROR;
439 }
440 }
Steve Block3762c312012-01-06 19:20:56 +0000441 ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 return INVALID_OPERATION;
443}
444
445status_t MediaPlayer::seekTo(int msec)
446{
Andreas Hubereffd8d52009-03-24 20:48:51 -0700447 mLockThreadId = getThreadId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 Mutex::Autolock _l(mLock);
Andreas Hubereffd8d52009-03-24 20:48:51 -0700449 status_t result = seekTo_l(msec);
450 mLockThreadId = 0;
451
452 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453}
454
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700455status_t MediaPlayer::reset_l()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 mLoop = false;
458 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
459 mPrepareSync = false;
460 if (mPlayer != 0) {
461 status_t ret = mPlayer->reset();
462 if (ret != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000463 ALOGE("reset() failed with return code (%d)", ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
465 } else {
466 mCurrentState = MEDIA_PLAYER_IDLE;
467 }
James Dongc5bba6c2010-11-18 12:23:58 -0800468 // setDataSource has to be called again to create a
469 // new mediaplayer.
470 mPlayer = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 return ret;
472 }
473 clear_l();
474 return NO_ERROR;
475}
476
John Grossman720aa282012-02-22 15:38:35 -0800477status_t MediaPlayer::doSetRetransmitEndpoint(const sp<IMediaPlayer>& player) {
478 Mutex::Autolock _l(mLock);
479
480 if (player == NULL) {
481 return UNKNOWN_ERROR;
482 }
483
484 if (mRetransmitEndpointValid) {
485 return player->setRetransmitEndpoint(&mRetransmitEndpoint);
486 }
487
488 return OK;
489}
490
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700491status_t MediaPlayer::reset()
492{
Steve Block71f2cf12011-10-20 11:56:00 +0100493 ALOGV("reset");
Jamie Gennisc85ca5d2011-07-13 12:59:34 -0700494 Mutex::Autolock _l(mLock);
495 return reset_l();
496}
497
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800498status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499{
Steve Block71f2cf12011-10-20 11:56:00 +0100500 ALOGV("MediaPlayer::setAudioStreamType");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 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
Steve Block3762c312012-01-06 19:20:56 +0000506 ALOGE("setAudioStream called in state %d", mCurrentState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 return INVALID_OPERATION;
508 }
509 // cache
510 mStreamType = type;
511 return OK;
512}
513
514status_t MediaPlayer::setLooping(int loop)
515{
Steve Block71f2cf12011-10-20 11:56:00 +0100516 ALOGV("MediaPlayer::setLooping");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 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() {
Steve Block71f2cf12011-10-20 11:56:00 +0100526 ALOGV("isLooping");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 Mutex::Autolock _l(mLock);
528 if (mPlayer != 0) {
529 return mLoop;
530 }
Steve Block71f2cf12011-10-20 11:56:00 +0100531 ALOGV("isLooping: no active player");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 return false;
533}
534
535status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
536{
Steve Block71f2cf12011-10-20 11:56:00 +0100537 ALOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 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 Laurent619346f2010-06-21 09:27:30 -0700547status_t MediaPlayer::setAudioSessionId(int sessionId)
548{
Steve Block71f2cf12011-10-20 11:56:00 +0100549 ALOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
Eric Laurent619346f2010-06-21 09:27:30 -0700550 Mutex::Autolock _l(mLock);
551 if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
Steve Block3762c312012-01-06 19:20:56 +0000552 ALOGE("setAudioSessionId called in state %d", mCurrentState);
Eric Laurent619346f2010-06-21 09:27:30 -0700553 return INVALID_OPERATION;
554 }
555 if (sessionId < 0) {
556 return BAD_VALUE;
557 }
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700558 if (sessionId != mAudioSessionId) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700559 AudioSystem::releaseAudioSessionId(mAudioSessionId);
560 AudioSystem::acquireAudioSessionId(sessionId);
561 mAudioSessionId = sessionId;
Marco Nelissenc74b93f2011-08-02 13:33:41 -0700562 }
Eric Laurent619346f2010-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 Laurent7070b362010-07-16 07:43:46 -0700572status_t MediaPlayer::setAuxEffectSendLevel(float level)
573{
Steve Block71f2cf12011-10-20 11:56:00 +0100574 ALOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
Eric Laurent7070b362010-07-16 07:43:46 -0700575 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{
Steve Block71f2cf12011-10-20 11:56:00 +0100585 ALOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
Eric Laurent7070b362010-07-16 07:43:46 -0700586 Mutex::Autolock _l(mLock);
587 if (mPlayer == 0 ||
588 (mCurrentState & MEDIA_PLAYER_IDLE) ||
589 (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
Steve Block3762c312012-01-06 19:20:56 +0000590 ALOGE("attachAuxEffect called in state %d", mCurrentState);
Eric Laurent7070b362010-07-16 07:43:46 -0700591 return INVALID_OPERATION;
592 }
593
594 return mPlayer->attachAuxEffect(effectId);
595}
596
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700597status_t MediaPlayer::setParameter(int key, const Parcel& request)
598{
Steve Block71f2cf12011-10-20 11:56:00 +0100599 ALOGV("MediaPlayer::setParameter(%d)", key);
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700600 Mutex::Autolock _l(mLock);
601 if (mPlayer != NULL) {
602 return mPlayer->setParameter(key, request);
603 }
Steve Block71f2cf12011-10-20 11:56:00 +0100604 ALOGV("setParameter: no active player");
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700605 return INVALID_OPERATION;
606}
607
608status_t MediaPlayer::getParameter(int key, Parcel *reply)
609{
Steve Block71f2cf12011-10-20 11:56:00 +0100610 ALOGV("MediaPlayer::getParameter(%d)", key);
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700611 Mutex::Autolock _l(mLock);
612 if (mPlayer != NULL) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700613 return mPlayer->getParameter(key, reply);
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700614 }
Steve Block71f2cf12011-10-20 11:56:00 +0100615 ALOGV("getParameter: no active player");
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700616 return INVALID_OPERATION;
617}
618
John Grossman720aa282012-02-22 15:38:35 -0800619status_t MediaPlayer::setRetransmitEndpoint(const char* addrString,
620 uint16_t port) {
621 ALOGV("MediaPlayer::setRetransmitEndpoint(%s:%hu)",
622 addrString ? addrString : "(null)", port);
623
624 Mutex::Autolock _l(mLock);
625 if ((mPlayer != NULL) || (mCurrentState != MEDIA_PLAYER_IDLE))
626 return INVALID_OPERATION;
627
628 if (NULL == addrString) {
629 mRetransmitEndpointValid = false;
630 return OK;
631 }
632
633 struct in_addr saddr;
634 if(!inet_aton(addrString, &saddr)) {
635 return BAD_VALUE;
636 }
637
638 memset(&mRetransmitEndpoint, 0, sizeof(&mRetransmitEndpoint));
639 mRetransmitEndpoint.sin_family = AF_INET;
640 mRetransmitEndpoint.sin_addr = saddr;
641 mRetransmitEndpoint.sin_port = htons(port);
642 mRetransmitEndpointValid = true;
643
644 return OK;
645}
646
Gloria Wang162ee492011-04-11 17:23:27 -0700647void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648{
Steve Block71f2cf12011-10-20 11:56:00 +0100649 ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 bool send = true;
Jason Samsebb020a2009-03-24 18:45:22 -0700651 bool locked = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652
653 // TODO: In the future, we might be on the same thread if the app is
654 // running in the same process as the media server. In that case,
655 // this will deadlock.
Nicolas Catania32f82772009-06-11 16:33:49 -0700656 //
Jason Samsebb020a2009-03-24 18:45:22 -0700657 // The threadId hack below works around this for the care of prepare
Andreas Hubereffd8d52009-03-24 20:48:51 -0700658 // and seekTo within the same process.
659 // FIXME: Remember, this is a hack, it's not even a hack that is applied
660 // consistently for all use-cases, this needs to be revisited.
Glenn Kasten18db49a2012-03-12 16:29:55 -0700661 if (mLockThreadId != getThreadId()) {
Jason Samsebb020a2009-03-24 18:45:22 -0700662 mLock.lock();
663 locked = true;
Nicolas Catania32f82772009-06-11 16:33:49 -0700664 }
Jason Samsebb020a2009-03-24 18:45:22 -0700665
Eric Laurent1d53b2a2010-08-03 07:49:49 -0700666 // Allows calls from JNI in idle state to notify errors
667 if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100668 ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Samsebb020a2009-03-24 18:45:22 -0700669 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 return;
671 }
672
673 switch (msg) {
674 case MEDIA_NOP: // interface test message
675 break;
676 case MEDIA_PREPARED:
Steve Block71f2cf12011-10-20 11:56:00 +0100677 ALOGV("prepared");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 mCurrentState = MEDIA_PLAYER_PREPARED;
679 if (mPrepareSync) {
Steve Block71f2cf12011-10-20 11:56:00 +0100680 ALOGV("signal application thread");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 mPrepareSync = false;
682 mPrepareStatus = NO_ERROR;
683 mSignal.signal();
684 }
685 break;
686 case MEDIA_PLAYBACK_COMPLETE:
Steve Block71f2cf12011-10-20 11:56:00 +0100687 ALOGV("playback complete");
Marco Nelissen3c473ea2010-09-17 15:04:01 -0700688 if (mCurrentState == MEDIA_PLAYER_IDLE) {
Steve Block3762c312012-01-06 19:20:56 +0000689 ALOGE("playback complete in idle state");
Marco Nelissen3c473ea2010-09-17 15:04:01 -0700690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 if (!mLoop) {
692 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
693 }
694 break;
695 case MEDIA_ERROR:
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700696 // Always log errors.
697 // ext1: Media framework error code.
698 // ext2: Implementation dependant error code.
Steve Block3762c312012-01-06 19:20:56 +0000699 ALOGE("error (%d, %d)", ext1, ext2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
701 if (mPrepareSync)
702 {
Steve Block71f2cf12011-10-20 11:56:00 +0100703 ALOGV("signal application thread");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 mPrepareSync = false;
705 mPrepareStatus = ext1;
706 mSignal.signal();
707 send = false;
708 }
709 break;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700710 case MEDIA_INFO:
711 // ext1: Media framework error code.
712 // ext2: Implementation dependant error code.
Andreas Huber52c78322011-01-11 15:05:28 -0800713 if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
Steve Block8564c8d2012-01-05 23:22:43 +0000714 ALOGW("info/warning (%d, %d)", ext1, ext2);
Andreas Huber52c78322011-01-11 15:05:28 -0800715 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700716 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 case MEDIA_SEEK_COMPLETE:
Steve Block71f2cf12011-10-20 11:56:00 +0100718 ALOGV("Received seek complete");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 if (mSeekPosition != mCurrentPosition) {
Steve Block71f2cf12011-10-20 11:56:00 +0100720 ALOGV("Executing queued seekTo(%d)", mSeekPosition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 mSeekPosition = -1;
722 seekTo_l(mCurrentPosition);
723 }
724 else {
Steve Block71f2cf12011-10-20 11:56:00 +0100725 ALOGV("All seeks complete - return to regularly scheduled program");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 mCurrentPosition = mSeekPosition = -1;
727 }
728 break;
729 case MEDIA_BUFFERING_UPDATE:
Steve Block71f2cf12011-10-20 11:56:00 +0100730 ALOGV("buffering %d", ext1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 break;
732 case MEDIA_SET_VIDEO_SIZE:
Steve Block71f2cf12011-10-20 11:56:00 +0100733 ALOGV("New video size %d x %d", ext1, ext2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 mVideoWidth = ext1;
735 mVideoHeight = ext2;
736 break;
Gloria Wang162ee492011-04-11 17:23:27 -0700737 case MEDIA_TIMED_TEXT:
Steve Block71f2cf12011-10-20 11:56:00 +0100738 ALOGV("Received timed text message");
Gloria Wang162ee492011-04-11 17:23:27 -0700739 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 default:
Steve Block71f2cf12011-10-20 11:56:00 +0100741 ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 break;
743 }
744
745 sp<MediaPlayerListener> listener = mListener;
Jason Samsebb020a2009-03-24 18:45:22 -0700746 if (locked) mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747
748 // this prevents re-entrant calls into client code
749 if ((listener != 0) && send) {
750 Mutex::Autolock _l(mNotifyLock);
Steve Block71f2cf12011-10-20 11:56:00 +0100751 ALOGV("callback application");
Gloria Wang162ee492011-04-11 17:23:27 -0700752 listener->notify(msg, ext1, ext2, obj);
Steve Block71f2cf12011-10-20 11:56:00 +0100753 ALOGV("back from callback");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 }
755}
756
Glenn Kasten1c5a89d2012-01-04 09:36:37 -0800757/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758{
Steve Block71f2cf12011-10-20 11:56:00 +0100759 ALOGV("decode(%s)", url);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 sp<IMemory> p;
761 const sp<IMediaPlayerService>& service = getMediaPlayerService();
762 if (service != 0) {
James Dong34bbc222010-01-15 18:13:58 -0800763 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 } else {
Steve Block3762c312012-01-06 19:20:56 +0000765 ALOGE("Unable to locate media service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
767 return p;
768
769}
770
James Dong34bbc222010-01-15 18:13:58 -0800771void MediaPlayer::died()
772{
Steve Block71f2cf12011-10-20 11:56:00 +0100773 ALOGV("died");
James Dong34bbc222010-01-15 18:13:58 -0800774 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
775}
776
Glenn Kasten1c5a89d2012-01-04 09:36:37 -0800777/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778{
Steve Block71f2cf12011-10-20 11:56:00 +0100779 ALOGV("decode(%d, %lld, %lld)", fd, offset, length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 sp<IMemory> p;
781 const sp<IMediaPlayerService>& service = getMediaPlayerService();
782 if (service != 0) {
James Dong34bbc222010-01-15 18:13:58 -0800783 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 } else {
Steve Block3762c312012-01-06 19:20:56 +0000785 ALOGE("Unable to locate media service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
787 return p;
788
789}
790
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791}; // namespace android