1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "NuPlayerDriver"
19 #include <inttypes.h>
20 #include <utils/Log.h>
21 #include <cutils/properties.h>
22
23 #include "NuPlayerDriver.h"
24
25 #include "NuPlayer.h"
26 #include "NuPlayerSource.h"
27
28 #include <media/stagefright/foundation/ADebug.h>
29 #include <media/stagefright/foundation/ALooper.h>
30 #include <media/stagefright/foundation/AUtils.h>
31 #include <media/stagefright/foundation/ByteUtils.h>
32 #include <media/stagefright/MediaClock.h>
33 #include <media/stagefright/MetaData.h>
34 #include <media/stagefright/Utils.h>
35
36 #include <media/IMediaAnalyticsService.h>
37
38 static const int kDumpLockRetries = 50;
39 static const int kDumpLockSleepUs = 20000;
40
41 namespace android {
42
43 // key for media statistics
44 static const char *kKeyPlayer = "nuplayer";
45 // attrs for media statistics
46 // NB: these are matched with public Java API constants defined
47 // in frameworks/base/media/java/android/media/MediaPlayer.java
48 // These must be kept synchronized with the constants there.
49 static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
50 static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
51 static const char *kPlayerWidth = "android.media.mediaplayer.width";
52 static const char *kPlayerHeight = "android.media.mediaplayer.height";
53 static const char *kPlayerFrames = "android.media.mediaplayer.frames";
54 static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
55 static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
56 static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
57 static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
58 static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
59 static const char *kPlayerError = "android.media.mediaplayer.err";
60 static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
61
62 // NB: These are not yet exposed as public Java API constants.
63 static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
64 static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
65 //
66 static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
67 static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
68 static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
69
70
NuPlayerDriver(pid_t pid)71 NuPlayerDriver::NuPlayerDriver(pid_t pid)
72 : mState(STATE_IDLE),
73 mIsAsyncPrepare(false),
74 mAsyncResult(UNKNOWN_ERROR),
75 mSetSurfaceInProgress(false),
76 mDurationUs(-1),
77 mPositionUs(-1),
78 mSeekInProgress(false),
79 mPlayingTimeUs(0),
80 mRebufferingTimeUs(0),
81 mRebufferingEvents(0),
82 mRebufferingAtExit(false),
83 mLooper(new ALooper),
84 mMediaClock(new MediaClock),
85 mPlayer(new NuPlayer(pid, mMediaClock)),
86 mPlayerFlags(0),
87 mAnalyticsItem(NULL),
88 mClientUid(-1),
89 mAtEOS(false),
90 mLooping(false),
91 mAutoLoop(false) {
92 ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
93 mLooper->setName("NuPlayerDriver Looper");
94
95 mMediaClock->init();
96
97 // set up an analytics record
98 mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
99
100 mLooper->start(
101 false, /* runOnCallingThread */
102 true, /* canCallJava */
103 PRIORITY_AUDIO);
104
105 mLooper->registerHandler(mPlayer);
106
107 mPlayer->init(this);
108 }
109
~NuPlayerDriver()110 NuPlayerDriver::~NuPlayerDriver() {
111 ALOGV("~NuPlayerDriver(%p)", this);
112 mLooper->stop();
113
114 // finalize any pending metrics, usually a no-op.
115 updateMetrics("destructor");
116 logMetrics("destructor");
117
118 if (mAnalyticsItem != NULL) {
119 delete mAnalyticsItem;
120 mAnalyticsItem = NULL;
121 }
122 }
123
initCheck()124 status_t NuPlayerDriver::initCheck() {
125 return OK;
126 }
127
setUID(uid_t uid)128 status_t NuPlayerDriver::setUID(uid_t uid) {
129 mPlayer->setUID(uid);
130 mClientUid = uid;
131 if (mAnalyticsItem) {
132 mAnalyticsItem->setUid(mClientUid);
133 }
134
135 return OK;
136 }
137
setDataSource(const sp<IMediaHTTPService> & httpService,const char * url,const KeyedVector<String8,String8> * headers)138 status_t NuPlayerDriver::setDataSource(
139 const sp<IMediaHTTPService> &httpService,
140 const char *url,
141 const KeyedVector<String8, String8> *headers) {
142 ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
143 Mutex::Autolock autoLock(mLock);
144
145 if (mState != STATE_IDLE) {
146 return INVALID_OPERATION;
147 }
148
149 mState = STATE_SET_DATASOURCE_PENDING;
150
151 mPlayer->setDataSourceAsync(httpService, url, headers);
152
153 while (mState == STATE_SET_DATASOURCE_PENDING) {
154 mCondition.wait(mLock);
155 }
156
157 return mAsyncResult;
158 }
159
setDataSource(int fd,int64_t offset,int64_t length)160 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
161 ALOGV("setDataSource(%p) file(%d)", this, fd);
162 Mutex::Autolock autoLock(mLock);
163
164 if (mState != STATE_IDLE) {
165 return INVALID_OPERATION;
166 }
167
168 mState = STATE_SET_DATASOURCE_PENDING;
169
170 mPlayer->setDataSourceAsync(fd, offset, length);
171
172 while (mState == STATE_SET_DATASOURCE_PENDING) {
173 mCondition.wait(mLock);
174 }
175
176 return mAsyncResult;
177 }
178
setDataSource(const sp<IStreamSource> & source)179 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
180 ALOGV("setDataSource(%p) stream source", this);
181 Mutex::Autolock autoLock(mLock);
182
183 if (mState != STATE_IDLE) {
184 return INVALID_OPERATION;
185 }
186
187 mState = STATE_SET_DATASOURCE_PENDING;
188
189 mPlayer->setDataSourceAsync(source);
190
191 while (mState == STATE_SET_DATASOURCE_PENDING) {
192 mCondition.wait(mLock);
193 }
194
195 return mAsyncResult;
196 }
197
setDataSource(const sp<DataSource> & source)198 status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) {
199 ALOGV("setDataSource(%p) callback source", this);
200 Mutex::Autolock autoLock(mLock);
201
202 if (mState != STATE_IDLE) {
203 return INVALID_OPERATION;
204 }
205
206 mState = STATE_SET_DATASOURCE_PENDING;
207
208 mPlayer->setDataSourceAsync(source);
209
210 while (mState == STATE_SET_DATASOURCE_PENDING) {
211 mCondition.wait(mLock);
212 }
213
214 return mAsyncResult;
215 }
216
setVideoSurfaceTexture(const sp<IGraphicBufferProducer> & bufferProducer)217 status_t NuPlayerDriver::setVideoSurfaceTexture(
218 const sp<IGraphicBufferProducer> &bufferProducer) {
219 ALOGV("setVideoSurfaceTexture(%p)", this);
220 Mutex::Autolock autoLock(mLock);
221
222 if (mSetSurfaceInProgress) {
223 return INVALID_OPERATION;
224 }
225
226 switch (mState) {
227 case STATE_SET_DATASOURCE_PENDING:
228 case STATE_RESET_IN_PROGRESS:
229 return INVALID_OPERATION;
230
231 default:
232 break;
233 }
234
235 mSetSurfaceInProgress = true;
236
237 mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
238
239 while (mSetSurfaceInProgress) {
240 mCondition.wait(mLock);
241 }
242
243 return OK;
244 }
245
getBufferingSettings(BufferingSettings * buffering)246 status_t NuPlayerDriver::getBufferingSettings(BufferingSettings* buffering) {
247 ALOGV("getBufferingSettings(%p)", this);
248 {
249 Mutex::Autolock autoLock(mLock);
250 if (mState == STATE_IDLE) {
251 return INVALID_OPERATION;
252 }
253 }
254
255 return mPlayer->getBufferingSettings(buffering);
256 }
257
setBufferingSettings(const BufferingSettings & buffering)258 status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) {
259 ALOGV("setBufferingSettings(%p)", this);
260 {
261 Mutex::Autolock autoLock(mLock);
262 if (mState == STATE_IDLE) {
263 return INVALID_OPERATION;
264 }
265 }
266
267 return mPlayer->setBufferingSettings(buffering);
268 }
269
prepare()270 status_t NuPlayerDriver::prepare() {
271 ALOGV("prepare(%p)", this);
272 Mutex::Autolock autoLock(mLock);
273 return prepare_l();
274 }
275
prepare_l()276 status_t NuPlayerDriver::prepare_l() {
277 switch (mState) {
278 case STATE_UNPREPARED:
279 mState = STATE_PREPARING;
280
281 // Make sure we're not posting any notifications, success or
282 // failure information is only communicated through our result
283 // code.
284 mIsAsyncPrepare = false;
285 mPlayer->prepareAsync();
286 while (mState == STATE_PREPARING) {
287 mCondition.wait(mLock);
288 }
289 return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
290 case STATE_STOPPED:
291 // this is really just paused. handle as seek to start
292 mAtEOS = false;
293 mState = STATE_STOPPED_AND_PREPARING;
294 mIsAsyncPrepare = false;
295 mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
296 true /* needNotify */);
297 while (mState == STATE_STOPPED_AND_PREPARING) {
298 mCondition.wait(mLock);
299 }
300 return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
301 default:
302 return INVALID_OPERATION;
303 };
304 }
305
prepareAsync()306 status_t NuPlayerDriver::prepareAsync() {
307 ALOGV("prepareAsync(%p)", this);
308 Mutex::Autolock autoLock(mLock);
309
310 switch (mState) {
311 case STATE_UNPREPARED:
312 mState = STATE_PREPARING;
313 mIsAsyncPrepare = true;
314 mPlayer->prepareAsync();
315 return OK;
316 case STATE_STOPPED:
317 // this is really just paused. handle as seek to start
318 mAtEOS = false;
319 mState = STATE_STOPPED_AND_PREPARING;
320 mIsAsyncPrepare = true;
321 mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
322 true /* needNotify */);
323 return OK;
324 default:
325 return INVALID_OPERATION;
326 };
327 }
328
start()329 status_t NuPlayerDriver::start() {
330 ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
331 Mutex::Autolock autoLock(mLock);
332 return start_l();
333 }
334
start_l()335 status_t NuPlayerDriver::start_l() {
336 switch (mState) {
337 case STATE_UNPREPARED:
338 {
339 status_t err = prepare_l();
340
341 if (err != OK) {
342 return err;
343 }
344
345 CHECK_EQ(mState, STATE_PREPARED);
346
347 // fall through
348 }
349
350 case STATE_PAUSED:
351 case STATE_STOPPED_AND_PREPARED:
352 case STATE_PREPARED:
353 {
354 mPlayer->start();
355
356 // fall through
357 }
358
359 case STATE_RUNNING:
360 {
361 if (mAtEOS) {
362 mPlayer->seekToAsync(0);
363 mAtEOS = false;
364 mPositionUs = -1;
365 }
366 break;
367 }
368
369 default:
370 return INVALID_OPERATION;
371 }
372
373 mState = STATE_RUNNING;
374
375 return OK;
376 }
377
stop()378 status_t NuPlayerDriver::stop() {
379 ALOGD("stop(%p)", this);
380 Mutex::Autolock autoLock(mLock);
381
382 switch (mState) {
383 case STATE_RUNNING:
384 mPlayer->pause();
385 // fall through
386
387 case STATE_PAUSED:
388 mState = STATE_STOPPED;
389 notifyListener_l(MEDIA_STOPPED);
390 break;
391
392 case STATE_PREPARED:
393 case STATE_STOPPED:
394 case STATE_STOPPED_AND_PREPARING:
395 case STATE_STOPPED_AND_PREPARED:
396 mState = STATE_STOPPED;
397 break;
398
399 default:
400 return INVALID_OPERATION;
401 }
402
403 return OK;
404 }
405
pause()406 status_t NuPlayerDriver::pause() {
407 ALOGD("pause(%p)", this);
408 // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
409 // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
410 // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
411 // getCurrentPosition here.
412 int unused;
413 getCurrentPosition(&unused);
414
415 Mutex::Autolock autoLock(mLock);
416
417 switch (mState) {
418 case STATE_PAUSED:
419 case STATE_PREPARED:
420 return OK;
421
422 case STATE_RUNNING:
423 mState = STATE_PAUSED;
424 notifyListener_l(MEDIA_PAUSED);
425 mPlayer->pause();
426 break;
427
428 default:
429 return INVALID_OPERATION;
430 }
431
432 return OK;
433 }
434
isPlaying()435 bool NuPlayerDriver::isPlaying() {
436 return mState == STATE_RUNNING && !mAtEOS;
437 }
438
setPlaybackSettings(const AudioPlaybackRate & rate)439 status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) {
440 status_t err = mPlayer->setPlaybackSettings(rate);
441 if (err == OK) {
442 // try to update position
443 int unused;
444 getCurrentPosition(&unused);
445 Mutex::Autolock autoLock(mLock);
446 if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
447 mState = STATE_PAUSED;
448 notifyListener_l(MEDIA_PAUSED);
449 } else if (rate.mSpeed != 0.f
450 && (mState == STATE_PAUSED
451 || mState == STATE_STOPPED_AND_PREPARED
452 || mState == STATE_PREPARED)) {
453 err = start_l();
454 }
455 }
456 return err;
457 }
458
getPlaybackSettings(AudioPlaybackRate * rate)459 status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) {
460 return mPlayer->getPlaybackSettings(rate);
461 }
462
setSyncSettings(const AVSyncSettings & sync,float videoFpsHint)463 status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
464 return mPlayer->setSyncSettings(sync, videoFpsHint);
465 }
466
getSyncSettings(AVSyncSettings * sync,float * videoFps)467 status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
468 return mPlayer->getSyncSettings(sync, videoFps);
469 }
470
seekTo(int msec,MediaPlayerSeekMode mode)471 status_t NuPlayerDriver::seekTo(int msec, MediaPlayerSeekMode mode) {
472 ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
473 Mutex::Autolock autoLock(mLock);
474
475 int64_t seekTimeUs = msec * 1000ll;
476
477 switch (mState) {
478 case STATE_PREPARED:
479 case STATE_STOPPED_AND_PREPARED:
480 case STATE_PAUSED:
481 case STATE_RUNNING:
482 {
483 mAtEOS = false;
484 mSeekInProgress = true;
485 // seeks can take a while, so we essentially paused
486 notifyListener_l(MEDIA_PAUSED);
487 mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
488 break;
489 }
490
491 default:
492 return INVALID_OPERATION;
493 }
494
495 mPositionUs = seekTimeUs;
496 return OK;
497 }
498
getCurrentPosition(int * msec)499 status_t NuPlayerDriver::getCurrentPosition(int *msec) {
500 int64_t tempUs = 0;
501 {
502 Mutex::Autolock autoLock(mLock);
503 if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
504 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
505 *msec = (int)divRound(tempUs, (int64_t)(1000));
506 return OK;
507 }
508 }
509
510 status_t ret = mPlayer->getCurrentPosition(&tempUs);
511
512 Mutex::Autolock autoLock(mLock);
513 // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
514 // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
515 // position value that's different the seek to position.
516 if (ret != OK) {
517 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
518 } else {
519 mPositionUs = tempUs;
520 }
521 *msec = (int)divRound(tempUs, (int64_t)(1000));
522 return OK;
523 }
524
getDuration(int * msec)525 status_t NuPlayerDriver::getDuration(int *msec) {
526 Mutex::Autolock autoLock(mLock);
527
528 if (mDurationUs < 0) {
529 return UNKNOWN_ERROR;
530 }
531
532 *msec = (mDurationUs + 500ll) / 1000;
533
534 return OK;
535 }
536
updateMetrics(const char * where)537 void NuPlayerDriver::updateMetrics(const char *where) {
538
539 if (where == NULL) {
540 where = "unknown";
541 }
542 ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
543
544 // gather the final stats for this record
545 Vector<sp<AMessage>> trackStats;
546 mPlayer->getStats(&trackStats);
547
548 if (trackStats.size() > 0) {
549 for (size_t i = 0; i < trackStats.size(); ++i) {
550 const sp<AMessage> &stats = trackStats.itemAt(i);
551
552 AString mime;
553 stats->findString("mime", &mime);
554
555 AString name;
556 stats->findString("component-name", &name);
557
558 if (mime.startsWith("video/")) {
559 int32_t width, height;
560 mAnalyticsItem->setCString(kPlayerVMime, mime.c_str());
561 if (!name.empty()) {
562 mAnalyticsItem->setCString(kPlayerVCodec, name.c_str());
563 }
564
565 if (stats->findInt32("width", &width)
566 && stats->findInt32("height", &height)) {
567 mAnalyticsItem->setInt32(kPlayerWidth, width);
568 mAnalyticsItem->setInt32(kPlayerHeight, height);
569 }
570
571 int64_t numFramesTotal = 0;
572 int64_t numFramesDropped = 0;
573 stats->findInt64("frames-total", &numFramesTotal);
574 stats->findInt64("frames-dropped-output", &numFramesDropped);
575
576 mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal);
577 mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
578
579
580 } else if (mime.startsWith("audio/")) {
581 mAnalyticsItem->setCString(kPlayerAMime, mime.c_str());
582 if (!name.empty()) {
583 mAnalyticsItem->setCString(kPlayerACodec, name.c_str());
584 }
585 }
586 }
587 }
588
589 // always provide duration and playing time, even if they have 0/unknown values.
590
591 // getDuration() uses mLock for mutex -- careful where we use it.
592 int duration_ms = -1;
593 getDuration(&duration_ms);
594 mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
595
596 mPlayer->updateInternalTimers();
597
598 mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
599
600 if (mRebufferingEvents != 0) {
601 mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
602 mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
603 mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
604 }
605
606 mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
607 }
608
609
logMetrics(const char * where)610 void NuPlayerDriver::logMetrics(const char *where) {
611 if (where == NULL) {
612 where = "unknown";
613 }
614 ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
615
616 if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
617 return;
618 }
619
620 // log only non-empty records
621 // we always updateMetrics() before we get here
622 // and that always injects 3 fields (duration, playing time, and
623 // datasource) into the record.
624 // So the canonical "empty" record has 3 elements in it.
625 if (mAnalyticsItem->count() > 3) {
626
627 mAnalyticsItem->selfrecord();
628
629 // re-init in case we prepare() and start() again.
630 delete mAnalyticsItem ;
631 mAnalyticsItem = new MediaAnalyticsItem("nuplayer");
632 if (mAnalyticsItem) {
633 mAnalyticsItem->setUid(mClientUid);
634 }
635 } else {
636 ALOGV("nothing to record (only %d fields)", mAnalyticsItem->count());
637 }
638 }
639
reset()640 status_t NuPlayerDriver::reset() {
641 ALOGD("reset(%p) at state %d", this, mState);
642
643 updateMetrics("reset");
644 logMetrics("reset");
645
646 Mutex::Autolock autoLock(mLock);
647
648 switch (mState) {
649 case STATE_IDLE:
650 return OK;
651
652 case STATE_SET_DATASOURCE_PENDING:
653 case STATE_RESET_IN_PROGRESS:
654 return INVALID_OPERATION;
655
656 case STATE_PREPARING:
657 {
658 CHECK(mIsAsyncPrepare);
659
660 notifyListener_l(MEDIA_PREPARED);
661 break;
662 }
663
664 default:
665 break;
666 }
667
668 if (mState != STATE_STOPPED) {
669 notifyListener_l(MEDIA_STOPPED);
670 }
671
672 if (property_get_bool("persist.debug.sf.stats", false)) {
673 Vector<String16> args;
674 dump(-1, args);
675 }
676
677 mState = STATE_RESET_IN_PROGRESS;
678 mPlayer->resetAsync();
679
680 while (mState == STATE_RESET_IN_PROGRESS) {
681 mCondition.wait(mLock);
682 }
683
684 mDurationUs = -1;
685 mPositionUs = -1;
686 mLooping = false;
687 mPlayingTimeUs = 0;
688 mRebufferingTimeUs = 0;
689 mRebufferingEvents = 0;
690 mRebufferingAtExit = false;
691
692 return OK;
693 }
694
notifyAt(int64_t mediaTimeUs)695 status_t NuPlayerDriver::notifyAt(int64_t mediaTimeUs) {
696 ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
697 return mPlayer->notifyAt(mediaTimeUs);
698 }
699
setLooping(int loop)700 status_t NuPlayerDriver::setLooping(int loop) {
701 mLooping = loop != 0;
702 return OK;
703 }
704
playerType()705 player_type NuPlayerDriver::playerType() {
706 return NU_PLAYER;
707 }
708
invoke(const Parcel & request,Parcel * reply)709 status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
710 if (reply == NULL) {
711 ALOGE("reply is a NULL pointer");
712 return BAD_VALUE;
713 }
714
715 int32_t methodId;
716 status_t ret = request.readInt32(&methodId);
717 if (ret != OK) {
718 ALOGE("Failed to retrieve the requested method to invoke");
719 return ret;
720 }
721
722 switch (methodId) {
723 case INVOKE_ID_SET_VIDEO_SCALING_MODE:
724 {
725 int mode = request.readInt32();
726 return mPlayer->setVideoScalingMode(mode);
727 }
728
729 case INVOKE_ID_GET_TRACK_INFO:
730 {
731 return mPlayer->getTrackInfo(reply);
732 }
733
734 case INVOKE_ID_SELECT_TRACK:
735 {
736 int trackIndex = request.readInt32();
737 int msec = 0;
738 // getCurrentPosition should always return OK
739 getCurrentPosition(&msec);
740 return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll);
741 }
742
743 case INVOKE_ID_UNSELECT_TRACK:
744 {
745 int trackIndex = request.readInt32();
746 return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
747 }
748
749 case INVOKE_ID_GET_SELECTED_TRACK:
750 {
751 int32_t type = request.readInt32();
752 return mPlayer->getSelectedTrack(type, reply);
753 }
754
755 default:
756 {
757 return INVALID_OPERATION;
758 }
759 }
760 }
761
setAudioSink(const sp<AudioSink> & audioSink)762 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
763 mPlayer->setAudioSink(audioSink);
764 mAudioSink = audioSink;
765 }
766
setParameter(int,const Parcel &)767 status_t NuPlayerDriver::setParameter(
768 int /* key */, const Parcel & /* request */) {
769 return INVALID_OPERATION;
770 }
771
getParameter(int key,Parcel * reply)772 status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
773
774 if (key == FOURCC('m','t','r','X')) {
775 // mtrX -- a play on 'metrics' (not matrix)
776 // gather current info all together, parcel it, and send it back
777 updateMetrics("api");
778 mAnalyticsItem->writeToParcel(reply);
779 return OK;
780 }
781
782 return INVALID_OPERATION;
783 }
784
getMetadata(const media::Metadata::Filter &,Parcel * records)785 status_t NuPlayerDriver::getMetadata(
786 const media::Metadata::Filter& /* ids */, Parcel *records) {
787 Mutex::Autolock autoLock(mLock);
788
789 using media::Metadata;
790
791 Metadata meta(records);
792
793 meta.appendBool(
794 Metadata::kPauseAvailable,
795 mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
796
797 meta.appendBool(
798 Metadata::kSeekBackwardAvailable,
799 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
800
801 meta.appendBool(
802 Metadata::kSeekForwardAvailable,
803 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
804
805 meta.appendBool(
806 Metadata::kSeekAvailable,
807 mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
808
809 return OK;
810 }
811
notifyResetComplete()812 void NuPlayerDriver::notifyResetComplete() {
813 ALOGD("notifyResetComplete(%p)", this);
814 Mutex::Autolock autoLock(mLock);
815
816 CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
817 mState = STATE_IDLE;
818 mCondition.broadcast();
819 }
820
notifySetSurfaceComplete()821 void NuPlayerDriver::notifySetSurfaceComplete() {
822 ALOGV("notifySetSurfaceComplete(%p)", this);
823 Mutex::Autolock autoLock(mLock);
824
825 CHECK(mSetSurfaceInProgress);
826 mSetSurfaceInProgress = false;
827
828 mCondition.broadcast();
829 }
830
notifyDuration(int64_t durationUs)831 void NuPlayerDriver::notifyDuration(int64_t durationUs) {
832 Mutex::Autolock autoLock(mLock);
833 mDurationUs = durationUs;
834 }
835
notifyMorePlayingTimeUs(int64_t playingUs)836 void NuPlayerDriver::notifyMorePlayingTimeUs(int64_t playingUs) {
837 Mutex::Autolock autoLock(mLock);
838 mPlayingTimeUs += playingUs;
839 }
840
notifyMoreRebufferingTimeUs(int64_t rebufferingUs)841 void NuPlayerDriver::notifyMoreRebufferingTimeUs(int64_t rebufferingUs) {
842 Mutex::Autolock autoLock(mLock);
843 mRebufferingTimeUs += rebufferingUs;
844 mRebufferingEvents++;
845 }
846
notifyRebufferingWhenExit(bool status)847 void NuPlayerDriver::notifyRebufferingWhenExit(bool status) {
848 Mutex::Autolock autoLock(mLock);
849 mRebufferingAtExit = status;
850 }
851
notifySeekComplete()852 void NuPlayerDriver::notifySeekComplete() {
853 ALOGV("notifySeekComplete(%p)", this);
854 Mutex::Autolock autoLock(mLock);
855 mSeekInProgress = false;
856 notifySeekComplete_l();
857 }
858
notifySeekComplete_l()859 void NuPlayerDriver::notifySeekComplete_l() {
860 bool wasSeeking = true;
861 if (mState == STATE_STOPPED_AND_PREPARING) {
862 wasSeeking = false;
863 mState = STATE_STOPPED_AND_PREPARED;
864 mCondition.broadcast();
865 if (!mIsAsyncPrepare) {
866 // if we are preparing synchronously, no need to notify listener
867 return;
868 }
869 } else if (mState == STATE_STOPPED) {
870 // no need to notify listener
871 return;
872 }
873 notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
874 }
875
dump(int fd,const Vector<String16> &) const876 status_t NuPlayerDriver::dump(
877 int fd, const Vector<String16> & /* args */) const {
878
879 Vector<sp<AMessage> > trackStats;
880 mPlayer->getStats(&trackStats);
881
882 AString logString(" NuPlayer\n");
883 char buf[256] = {0};
884
885 bool locked = false;
886 for (int i = 0; i < kDumpLockRetries; ++i) {
887 if (mLock.tryLock() == NO_ERROR) {
888 locked = true;
889 break;
890 }
891 usleep(kDumpLockSleepUs);
892 }
893
894 if (locked) {
895 snprintf(buf, sizeof(buf), " state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
896 mState, mAtEOS, mLooping, mAutoLoop);
897 mLock.unlock();
898 } else {
899 snprintf(buf, sizeof(buf), " NPD(%p) lock is taken\n", this);
900 }
901 logString.append(buf);
902
903 for (size_t i = 0; i < trackStats.size(); ++i) {
904 const sp<AMessage> &stats = trackStats.itemAt(i);
905
906 AString mime;
907 if (stats->findString("mime", &mime)) {
908 snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str());
909 logString.append(buf);
910 }
911
912 AString name;
913 if (stats->findString("component-name", &name)) {
914 snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str());
915 logString.append(buf);
916 }
917
918 if (mime.startsWith("video/")) {
919 int32_t width, height;
920 if (stats->findInt32("width", &width)
921 && stats->findInt32("height", &height)) {
922 snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height);
923 logString.append(buf);
924 }
925
926 int64_t numFramesTotal = 0;
927 int64_t numFramesDropped = 0;
928
929 stats->findInt64("frames-total", &numFramesTotal);
930 stats->findInt64("frames-dropped-output", &numFramesDropped);
931 snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), "
932 "percentageDropped(%.2f%%)\n",
933 (long long)numFramesTotal,
934 (long long)numFramesDropped,
935 numFramesTotal == 0
936 ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
937 logString.append(buf);
938 }
939 }
940
941 ALOGI("%s", logString.c_str());
942
943 if (fd >= 0) {
944 FILE *out = fdopen(dup(fd), "w");
945 fprintf(out, "%s", logString.c_str());
946 fclose(out);
947 out = NULL;
948 }
949
950 return OK;
951 }
952
notifyListener(int msg,int ext1,int ext2,const Parcel * in)953 void NuPlayerDriver::notifyListener(
954 int msg, int ext1, int ext2, const Parcel *in) {
955 Mutex::Autolock autoLock(mLock);
956 notifyListener_l(msg, ext1, ext2, in);
957 }
958
notifyListener_l(int msg,int ext1,int ext2,const Parcel * in)959 void NuPlayerDriver::notifyListener_l(
960 int msg, int ext1, int ext2, const Parcel *in) {
961 ALOGD("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
962 this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
963 switch (msg) {
964 case MEDIA_PLAYBACK_COMPLETE:
965 {
966 if (mState != STATE_RESET_IN_PROGRESS) {
967 if (mAutoLoop) {
968 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
969 if (mAudioSink != NULL) {
970 streamType = mAudioSink->getAudioStreamType();
971 }
972 if (streamType == AUDIO_STREAM_NOTIFICATION) {
973 ALOGW("disabling auto-loop for notification");
974 mAutoLoop = false;
975 }
976 }
977 if (mLooping || mAutoLoop) {
978 mPlayer->seekToAsync(0);
979 if (mAudioSink != NULL) {
980 // The renderer has stopped the sink at the end in order to play out
981 // the last little bit of audio. If we're looping, we need to restart it.
982 mAudioSink->start();
983 }
984 // don't send completion event when looping
985 return;
986 }
987 if (property_get_bool("persist.debug.sf.stats", false)) {
988 Vector<String16> args;
989 dump(-1, args);
990 }
991 mPlayer->pause();
992 mState = STATE_PAUSED;
993 }
994 // fall through
995 }
996
997 case MEDIA_ERROR:
998 {
999 // when we have an error, add it to the analytics for this playback.
1000 // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
1001 // [test against msg is due to fall through from previous switch value]
1002 if (msg == MEDIA_ERROR) {
1003 mAnalyticsItem->setInt32(kPlayerError, ext1);
1004 if (ext2 != 0) {
1005 mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
1006 }
1007 mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
1008 }
1009 mAtEOS = true;
1010 break;
1011 }
1012
1013 default:
1014 break;
1015 }
1016
1017 mLock.unlock();
1018 sendEvent(msg, ext1, ext2, in);
1019 mLock.lock();
1020 }
1021
notifySetDataSourceCompleted(status_t err)1022 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
1023 Mutex::Autolock autoLock(mLock);
1024
1025 CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
1026
1027 mAsyncResult = err;
1028 mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
1029 mCondition.broadcast();
1030 }
1031
notifyPrepareCompleted(status_t err)1032 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
1033 ALOGV("notifyPrepareCompleted %d", err);
1034
1035 Mutex::Autolock autoLock(mLock);
1036
1037 if (mState != STATE_PREPARING) {
1038 // We were preparing asynchronously when the client called
1039 // reset(), we sent a premature "prepared" notification and
1040 // then initiated the reset. This notification is stale.
1041 CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
1042 return;
1043 }
1044
1045 CHECK_EQ(mState, STATE_PREPARING);
1046
1047 mAsyncResult = err;
1048
1049 if (err == OK) {
1050 // update state before notifying client, so that if client calls back into NuPlayerDriver
1051 // in response, NuPlayerDriver has the right state
1052 mState = STATE_PREPARED;
1053 if (mIsAsyncPrepare) {
1054 notifyListener_l(MEDIA_PREPARED);
1055 }
1056 } else {
1057 mState = STATE_UNPREPARED;
1058 if (mIsAsyncPrepare) {
1059 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1060 }
1061 }
1062
1063 sp<MetaData> meta = mPlayer->getFileMeta();
1064 int32_t loop;
1065 if (meta != NULL
1066 && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
1067 mAutoLoop = true;
1068 }
1069
1070 mCondition.broadcast();
1071 }
1072
notifyFlagsChanged(uint32_t flags)1073 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
1074 Mutex::Autolock autoLock(mLock);
1075
1076 mPlayerFlags = flags;
1077 }
1078
1079 // Modular DRM
prepareDrm(const uint8_t uuid[16],const Vector<uint8_t> & drmSessionId)1080 status_t NuPlayerDriver::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
1081 {
1082 ALOGV("prepareDrm(%p) state: %d", this, mState);
1083
1084 // leaving the state verification for mediaplayer.cpp
1085 status_t ret = mPlayer->prepareDrm(uuid, drmSessionId);
1086
1087 ALOGV("prepareDrm ret: %d", ret);
1088
1089 return ret;
1090 }
1091
releaseDrm()1092 status_t NuPlayerDriver::releaseDrm()
1093 {
1094 ALOGV("releaseDrm(%p) state: %d", this, mState);
1095
1096 // leaving the state verification for mediaplayer.cpp
1097 status_t ret = mPlayer->releaseDrm();
1098
1099 ALOGV("releaseDrm ret: %d", ret);
1100
1101 return ret;
1102 }
1103
stateString(State state)1104 std::string NuPlayerDriver::stateString(State state) {
1105 const char *rval = NULL;
1106 char rawbuffer[16]; // allows "%d"
1107
1108 switch (state) {
1109 case STATE_IDLE: rval = "IDLE"; break;
1110 case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
1111 case STATE_UNPREPARED: rval = "UNPREPARED"; break;
1112 case STATE_PREPARING: rval = "PREPARING"; break;
1113 case STATE_PREPARED: rval = "PREPARED"; break;
1114 case STATE_RUNNING: rval = "RUNNING"; break;
1115 case STATE_PAUSED: rval = "PAUSED"; break;
1116 case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
1117 case STATE_STOPPED: rval = "STOPPED"; break;
1118 case STATE_STOPPED_AND_PREPARING: rval = "STOPPED_AND_PREPARING"; break;
1119 case STATE_STOPPED_AND_PREPARED: rval = "STOPPED_AND_PREPARED"; break;
1120 default:
1121 // yes, this buffer is shared and vulnerable to races
1122 snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
1123 rval = rawbuffer;
1124 break;
1125 }
1126
1127 return rval;
1128 }
1129
1130 } // namespace android
1131