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