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