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