blob: ccfcc4771b907fe3601ed2dac18227467d05d601 [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);
132 mAnalyticsItem->generateSessionID();
133
Wei Jia12b9f4a2017-12-13 15:24:13 -0800134 mNuPlayer2Looper->start(
Wei Jia53692fa2017-12-11 10:33:46 -0800135 false, /* runOnCallingThread */
136 true, /* canCallJava */
137 PRIORITY_AUDIO);
138
Wei Jia12b9f4a2017-12-13 15:24:13 -0800139 mNuPlayer2Looper->registerHandler(mPlayer);
Wei Jia53692fa2017-12-11 10:33:46 -0800140
141 mPlayer->setDriver(this);
142}
143
144NuPlayer2Driver::~NuPlayer2Driver() {
145 ALOGV("~NuPlayer2Driver(%p)", this);
Wei Jia12b9f4a2017-12-13 15:24:13 -0800146 mNuPlayer2Looper->stop();
Wei Jia53692fa2017-12-11 10:33:46 -0800147 mLooper->stop();
148
149 // finalize any pending metrics, usually a no-op.
150 updateMetrics("destructor");
151 logMetrics("destructor");
152
153 if (mAnalyticsItem != NULL) {
154 delete mAnalyticsItem;
155 mAnalyticsItem = NULL;
156 }
157}
158
159status_t NuPlayer2Driver::initCheck() {
Wei Jia12b9f4a2017-12-13 15:24:13 -0800160 mLooper->start(
161 false, /* runOnCallingThread */
162 true, /* canCallJava */
163 PRIORITY_AUDIO);
164
165 mLooper->registerHandler(this);
Wei Jia53692fa2017-12-11 10:33:46 -0800166 return OK;
167}
168
169status_t NuPlayer2Driver::setUID(uid_t uid) {
170 mPlayer->setUID(uid);
171 mClientUid = uid;
172 if (mAnalyticsItem) {
173 mAnalyticsItem->setUid(mClientUid);
174 }
175
176 return OK;
177}
178
179status_t NuPlayer2Driver::setDataSource(
180 const sp<MediaHTTPService> &httpService,
181 const char *url,
182 const KeyedVector<String8, String8> *headers) {
183 ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
184 Mutex::Autolock autoLock(mLock);
185
186 if (mState != STATE_IDLE) {
187 return INVALID_OPERATION;
188 }
189
190 mState = STATE_SET_DATASOURCE_PENDING;
191
192 mPlayer->setDataSourceAsync(httpService, url, headers);
193
194 while (mState == STATE_SET_DATASOURCE_PENDING) {
195 mCondition.wait(mLock);
196 }
197
198 return mAsyncResult;
199}
200
201status_t NuPlayer2Driver::setDataSource(int fd, int64_t offset, int64_t length) {
202 ALOGV("setDataSource(%p) file(%d)", this, fd);
203 Mutex::Autolock autoLock(mLock);
204
205 if (mState != STATE_IDLE) {
206 return INVALID_OPERATION;
207 }
208
209 mState = STATE_SET_DATASOURCE_PENDING;
210
211 mPlayer->setDataSourceAsync(fd, offset, length);
212
213 while (mState == STATE_SET_DATASOURCE_PENDING) {
214 mCondition.wait(mLock);
215 }
216
217 return mAsyncResult;
218}
219
220status_t NuPlayer2Driver::setDataSource(const sp<IStreamSource> &source) {
221 ALOGV("setDataSource(%p) stream source", this);
222 Mutex::Autolock autoLock(mLock);
223
224 if (mState != STATE_IDLE) {
225 return INVALID_OPERATION;
226 }
227
228 mState = STATE_SET_DATASOURCE_PENDING;
229
230 mPlayer->setDataSourceAsync(source);
231
232 while (mState == STATE_SET_DATASOURCE_PENDING) {
233 mCondition.wait(mLock);
234 }
235
236 return mAsyncResult;
237}
238
239status_t NuPlayer2Driver::setDataSource(const sp<DataSource> &source) {
240 ALOGV("setDataSource(%p) callback source", this);
241 Mutex::Autolock autoLock(mLock);
242
243 if (mState != STATE_IDLE) {
244 return INVALID_OPERATION;
245 }
246
247 mState = STATE_SET_DATASOURCE_PENDING;
248
249 mPlayer->setDataSourceAsync(source);
250
251 while (mState == STATE_SET_DATASOURCE_PENDING) {
252 mCondition.wait(mLock);
253 }
254
255 return mAsyncResult;
256}
257
Wei Jia28288fb2017-12-15 13:45:29 -0800258status_t NuPlayer2Driver::setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) {
Wei Jia53692fa2017-12-11 10:33:46 -0800259 ALOGV("setVideoSurfaceTexture(%p)", this);
260 Mutex::Autolock autoLock(mLock);
261
262 if (mSetSurfaceInProgress) {
263 return INVALID_OPERATION;
264 }
265
266 switch (mState) {
267 case STATE_SET_DATASOURCE_PENDING:
268 case STATE_RESET_IN_PROGRESS:
269 return INVALID_OPERATION;
270
271 default:
272 break;
273 }
274
275 mSetSurfaceInProgress = true;
276
Wei Jia28288fb2017-12-15 13:45:29 -0800277 mPlayer->setVideoSurfaceTextureAsync(nww);
Wei Jia53692fa2017-12-11 10:33:46 -0800278
279 while (mSetSurfaceInProgress) {
280 mCondition.wait(mLock);
281 }
282
283 return OK;
284}
285
286status_t NuPlayer2Driver::getBufferingSettings(BufferingSettings* buffering) {
287 ALOGV("getBufferingSettings(%p)", this);
288 {
289 Mutex::Autolock autoLock(mLock);
290 if (mState == STATE_IDLE) {
291 return INVALID_OPERATION;
292 }
293 }
294
295 return mPlayer->getBufferingSettings(buffering);
296}
297
298status_t NuPlayer2Driver::setBufferingSettings(const BufferingSettings& buffering) {
299 ALOGV("setBufferingSettings(%p)", this);
300 {
301 Mutex::Autolock autoLock(mLock);
302 if (mState == STATE_IDLE) {
303 return INVALID_OPERATION;
304 }
305 }
306
307 return mPlayer->setBufferingSettings(buffering);
308}
309
310status_t NuPlayer2Driver::prepare() {
311 ALOGV("prepare(%p)", this);
312 Mutex::Autolock autoLock(mLock);
313 return prepare_l();
314}
315
316status_t NuPlayer2Driver::prepare_l() {
317 switch (mState) {
318 case STATE_UNPREPARED:
319 mState = STATE_PREPARING;
320
321 // Make sure we're not posting any notifications, success or
322 // failure information is only communicated through our result
323 // code.
324 mIsAsyncPrepare = false;
325 mPlayer->prepareAsync();
326 while (mState == STATE_PREPARING) {
327 mCondition.wait(mLock);
328 }
329 return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
330 case STATE_STOPPED:
331 // this is really just paused. handle as seek to start
332 mAtEOS = false;
333 mState = STATE_STOPPED_AND_PREPARING;
334 mIsAsyncPrepare = false;
335 mPlayer->seekToAsync(0, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
336 true /* needNotify */);
337 while (mState == STATE_STOPPED_AND_PREPARING) {
338 mCondition.wait(mLock);
339 }
340 return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
341 default:
342 return INVALID_OPERATION;
343 };
344}
345
346status_t NuPlayer2Driver::prepareAsync() {
347 ALOGV("prepareAsync(%p)", this);
348 Mutex::Autolock autoLock(mLock);
349
350 switch (mState) {
351 case STATE_UNPREPARED:
352 mState = STATE_PREPARING;
353 mIsAsyncPrepare = true;
354 mPlayer->prepareAsync();
355 return OK;
356 case STATE_STOPPED:
357 // this is really just paused. handle as seek to start
358 mAtEOS = false;
359 mState = STATE_STOPPED_AND_PREPARING;
360 mIsAsyncPrepare = true;
361 mPlayer->seekToAsync(0, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
362 true /* needNotify */);
363 return OK;
364 default:
365 return INVALID_OPERATION;
366 };
367}
368
369status_t NuPlayer2Driver::start() {
370 ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
371 Mutex::Autolock autoLock(mLock);
372 return start_l();
373}
374
375status_t NuPlayer2Driver::start_l() {
376 switch (mState) {
377 case STATE_UNPREPARED:
378 {
379 status_t err = prepare_l();
380
381 if (err != OK) {
382 return err;
383 }
384
385 CHECK_EQ(mState, STATE_PREPARED);
386
387 // fall through
388 }
389
390 case STATE_PAUSED:
391 case STATE_STOPPED_AND_PREPARED:
392 case STATE_PREPARED:
393 {
394 mPlayer->start();
395
396 // fall through
397 }
398
399 case STATE_RUNNING:
400 {
401 if (mAtEOS) {
402 mPlayer->seekToAsync(0);
403 mAtEOS = false;
404 mPositionUs = -1;
405 }
406 break;
407 }
408
409 default:
410 return INVALID_OPERATION;
411 }
412
413 mState = STATE_RUNNING;
414
415 return OK;
416}
417
418status_t NuPlayer2Driver::stop() {
419 ALOGD("stop(%p)", this);
420 Mutex::Autolock autoLock(mLock);
421
422 switch (mState) {
423 case STATE_RUNNING:
424 mPlayer->pause();
425 // fall through
426
427 case STATE_PAUSED:
428 mState = STATE_STOPPED;
Wei Jiac5c79da2017-12-21 18:03:05 -0800429 notifyListener_l(MEDIA2_STOPPED);
Wei Jia53692fa2017-12-11 10:33:46 -0800430 break;
431
432 case STATE_PREPARED:
433 case STATE_STOPPED:
434 case STATE_STOPPED_AND_PREPARING:
435 case STATE_STOPPED_AND_PREPARED:
436 mState = STATE_STOPPED;
437 break;
438
439 default:
440 return INVALID_OPERATION;
441 }
442
443 return OK;
444}
445
446status_t NuPlayer2Driver::pause() {
447 ALOGD("pause(%p)", this);
448 // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
449 // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
450 // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
451 // getCurrentPosition here.
452 int unused;
453 getCurrentPosition(&unused);
454
455 Mutex::Autolock autoLock(mLock);
456
457 switch (mState) {
458 case STATE_PAUSED:
459 case STATE_PREPARED:
460 return OK;
461
462 case STATE_RUNNING:
463 mState = STATE_PAUSED;
Wei Jiac5c79da2017-12-21 18:03:05 -0800464 notifyListener_l(MEDIA2_PAUSED);
Wei Jia53692fa2017-12-11 10:33:46 -0800465 mPlayer->pause();
466 break;
467
468 default:
469 return INVALID_OPERATION;
470 }
471
472 return OK;
473}
474
475bool NuPlayer2Driver::isPlaying() {
476 return mState == STATE_RUNNING && !mAtEOS;
477}
478
479status_t NuPlayer2Driver::setPlaybackSettings(const AudioPlaybackRate &rate) {
480 status_t err = mPlayer->setPlaybackSettings(rate);
481 if (err == OK) {
482 // try to update position
483 int unused;
484 getCurrentPosition(&unused);
485 Mutex::Autolock autoLock(mLock);
486 if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
487 mState = STATE_PAUSED;
Wei Jiac5c79da2017-12-21 18:03:05 -0800488 notifyListener_l(MEDIA2_PAUSED);
Wei Jia53692fa2017-12-11 10:33:46 -0800489 } else if (rate.mSpeed != 0.f
490 && (mState == STATE_PAUSED
491 || mState == STATE_STOPPED_AND_PREPARED
492 || mState == STATE_PREPARED)) {
493 err = start_l();
494 }
495 }
496 return err;
497}
498
499status_t NuPlayer2Driver::getPlaybackSettings(AudioPlaybackRate *rate) {
500 return mPlayer->getPlaybackSettings(rate);
501}
502
503status_t NuPlayer2Driver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
504 return mPlayer->setSyncSettings(sync, videoFpsHint);
505}
506
507status_t NuPlayer2Driver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
508 return mPlayer->getSyncSettings(sync, videoFps);
509}
510
511status_t NuPlayer2Driver::seekTo(int msec, MediaPlayer2SeekMode mode) {
512 ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
513 Mutex::Autolock autoLock(mLock);
514
515 int64_t seekTimeUs = msec * 1000ll;
516
517 switch (mState) {
518 case STATE_PREPARED:
519 case STATE_STOPPED_AND_PREPARED:
520 case STATE_PAUSED:
521 case STATE_RUNNING:
522 {
523 mAtEOS = false;
524 mSeekInProgress = true;
525 // seeks can take a while, so we essentially paused
Wei Jiac5c79da2017-12-21 18:03:05 -0800526 notifyListener_l(MEDIA2_PAUSED);
Wei Jia53692fa2017-12-11 10:33:46 -0800527 mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
528 break;
529 }
530
531 default:
532 return INVALID_OPERATION;
533 }
534
535 mPositionUs = seekTimeUs;
536 return OK;
537}
538
539status_t NuPlayer2Driver::getCurrentPosition(int *msec) {
540 int64_t tempUs = 0;
541 {
542 Mutex::Autolock autoLock(mLock);
543 if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
544 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
545 *msec = (int)divRound(tempUs, (int64_t)(1000));
546 return OK;
547 }
548 }
549
550 status_t ret = mPlayer->getCurrentPosition(&tempUs);
551
552 Mutex::Autolock autoLock(mLock);
553 // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
554 // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
555 // position value that's different the seek to position.
556 if (ret != OK) {
557 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
558 } else {
559 mPositionUs = tempUs;
560 }
561 *msec = (int)divRound(tempUs, (int64_t)(1000));
562 return OK;
563}
564
565status_t NuPlayer2Driver::getDuration(int *msec) {
566 Mutex::Autolock autoLock(mLock);
567
568 if (mDurationUs < 0) {
569 return UNKNOWN_ERROR;
570 }
571
572 *msec = (mDurationUs + 500ll) / 1000;
573
574 return OK;
575}
576
577void NuPlayer2Driver::updateMetrics(const char *where) {
578 if (where == NULL) {
579 where = "unknown";
580 }
581 ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
582
583 // gather the final stats for this record
584 Vector<sp<AMessage>> trackStats;
585 mPlayer->getStats(&trackStats);
586
587 if (trackStats.size() > 0) {
588 for (size_t i = 0; i < trackStats.size(); ++i) {
589 const sp<AMessage> &stats = trackStats.itemAt(i);
590
591 AString mime;
592 stats->findString("mime", &mime);
593
594 AString name;
595 stats->findString("component-name", &name);
596
597 if (mime.startsWith("video/")) {
598 int32_t width, height;
599 mAnalyticsItem->setCString(kPlayerVMime, mime.c_str());
600 if (!name.empty()) {
601 mAnalyticsItem->setCString(kPlayerVCodec, name.c_str());
602 }
603
604 if (stats->findInt32("width", &width)
605 && stats->findInt32("height", &height)) {
606 mAnalyticsItem->setInt32(kPlayerWidth, width);
607 mAnalyticsItem->setInt32(kPlayerHeight, height);
608 }
609
610 int64_t numFramesTotal = 0;
611 int64_t numFramesDropped = 0;
612 stats->findInt64("frames-total", &numFramesTotal);
613 stats->findInt64("frames-dropped-output", &numFramesDropped);
614
615 mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal);
616 mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
617
618
619 } else if (mime.startsWith("audio/")) {
620 mAnalyticsItem->setCString(kPlayerAMime, mime.c_str());
621 if (!name.empty()) {
622 mAnalyticsItem->setCString(kPlayerACodec, name.c_str());
623 }
624 }
625 }
626 }
627
628 // always provide duration and playing time, even if they have 0/unknown values.
629
630 // getDuration() uses mLock for mutex -- careful where we use it.
631 int duration_ms = -1;
632 getDuration(&duration_ms);
633 mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
634
635 mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
636
637 if (mRebufferingEvents != 0) {
638 mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
639 mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
640 mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
641 }
642
643 mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
644}
645
646
647void NuPlayer2Driver::logMetrics(const char *where) {
648 if (where == NULL) {
649 where = "unknown";
650 }
651 ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
652
653 if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
654 return;
655 }
656
657 // log only non-empty records
658 // we always updateMetrics() before we get here
659 // and that always injects 3 fields (duration, playing time, and
660 // datasource) into the record.
661 // So the canonical "empty" record has 3 elements in it.
662 if (mAnalyticsItem->count() > 3) {
663
664 mAnalyticsItem->setFinalized(true);
665 mAnalyticsItem->selfrecord();
666
667 // re-init in case we prepare() and start() again.
668 delete mAnalyticsItem ;
Ray Essickee54eef2018-01-24 11:16:54 -0800669 mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
Wei Jia53692fa2017-12-11 10:33:46 -0800670 if (mAnalyticsItem) {
671 mAnalyticsItem->generateSessionID();
672 mAnalyticsItem->setUid(mClientUid);
673 }
674 } else {
675 ALOGV("did not have anything to record");
676 }
677}
678
679status_t NuPlayer2Driver::reset() {
680 ALOGD("reset(%p) at state %d", this, mState);
681
682 updateMetrics("reset");
683 logMetrics("reset");
684
685 Mutex::Autolock autoLock(mLock);
686
687 switch (mState) {
688 case STATE_IDLE:
689 return OK;
690
691 case STATE_SET_DATASOURCE_PENDING:
692 case STATE_RESET_IN_PROGRESS:
693 return INVALID_OPERATION;
694
695 case STATE_PREPARING:
696 {
697 CHECK(mIsAsyncPrepare);
698
Wei Jiac5c79da2017-12-21 18:03:05 -0800699 notifyListener_l(MEDIA2_PREPARED);
Wei Jia53692fa2017-12-11 10:33:46 -0800700 break;
701 }
702
703 default:
704 break;
705 }
706
707 if (mState != STATE_STOPPED) {
Wei Jiac5c79da2017-12-21 18:03:05 -0800708 notifyListener_l(MEDIA2_STOPPED);
Wei Jia53692fa2017-12-11 10:33:46 -0800709 }
710
711 mState = STATE_RESET_IN_PROGRESS;
712 mPlayer->resetAsync();
713
714 while (mState == STATE_RESET_IN_PROGRESS) {
715 mCondition.wait(mLock);
716 }
717
718 mDurationUs = -1;
719 mPositionUs = -1;
720 mLooping = false;
721 mPlayingTimeUs = 0;
722 mRebufferingTimeUs = 0;
723 mRebufferingEvents = 0;
724 mRebufferingAtExit = false;
725
726 return OK;
727}
728
729status_t NuPlayer2Driver::notifyAt(int64_t mediaTimeUs) {
730 ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
731 return mPlayer->notifyAt(mediaTimeUs);
732}
733
734status_t NuPlayer2Driver::setLooping(int loop) {
735 mLooping = loop != 0;
736 return OK;
737}
738
739player2_type NuPlayer2Driver::playerType() {
740 return PLAYER2_NU_PLAYER2;
741}
742
743status_t NuPlayer2Driver::invoke(const Parcel &request, Parcel *reply) {
744 if (reply == NULL) {
745 ALOGE("reply is a NULL pointer");
746 return BAD_VALUE;
747 }
748
749 int32_t methodId;
750 status_t ret = request.readInt32(&methodId);
751 if (ret != OK) {
Wei Jia12b9f4a2017-12-13 15:24:13 -0800752 ALOGE("Failed to retrieve the requested method to invoke, err(%d)", ret);
Wei Jia53692fa2017-12-11 10:33:46 -0800753 return ret;
754 }
755
756 switch (methodId) {
757 case MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE:
758 {
759 int mode = request.readInt32();
760 return mPlayer->setVideoScalingMode(mode);
761 }
762
763 case MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO:
764 {
765 return mPlayer->getTrackInfo(reply);
766 }
767
768 case MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK:
769 {
770 int trackIndex = request.readInt32();
771 int msec = 0;
772 // getCurrentPosition should always return OK
773 getCurrentPosition(&msec);
774 return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll);
775 }
776
777 case MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK:
778 {
779 int trackIndex = request.readInt32();
780 return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
781 }
782
783 case MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK:
784 {
785 int32_t type = request.readInt32();
786 return mPlayer->getSelectedTrack(type, reply);
787 }
788
789 default:
790 {
791 return INVALID_OPERATION;
792 }
793 }
794}
795
796void NuPlayer2Driver::setAudioSink(const sp<AudioSink> &audioSink) {
797 mPlayer->setAudioSink(audioSink);
798 mAudioSink = audioSink;
799}
800
801status_t NuPlayer2Driver::setParameter(
802 int /* key */, const Parcel & /* request */) {
803 return INVALID_OPERATION;
804}
805
806status_t NuPlayer2Driver::getParameter(int key, Parcel *reply) {
807
808 if (key == FOURCC('m','t','r','X')) {
809 // mtrX -- a play on 'metrics' (not matrix)
810 // gather current info all together, parcel it, and send it back
811 updateMetrics("api");
812 mAnalyticsItem->writeToParcel(reply);
813 return OK;
814 }
815
816 return INVALID_OPERATION;
817}
818
819status_t NuPlayer2Driver::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 & NuPlayer2::Source::FLAG_CAN_PAUSE);
830
831 meta.appendBool(
832 Metadata::kSeekBackwardAvailable,
833 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK_BACKWARD);
834
835 meta.appendBool(
836 Metadata::kSeekForwardAvailable,
837 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK_FORWARD);
838
839 meta.appendBool(
840 Metadata::kSeekAvailable,
841 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK);
842
843 return OK;
844}
845
846void NuPlayer2Driver::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
855void NuPlayer2Driver::notifySetSurfaceComplete() {
856 ALOGV("notifySetSurfaceComplete(%p)", this);
857 Mutex::Autolock autoLock(mLock);
858
859 CHECK(mSetSurfaceInProgress);
860 mSetSurfaceInProgress = false;
861
862 mCondition.broadcast();
863}
864
865void NuPlayer2Driver::notifyDuration(int64_t durationUs) {
866 Mutex::Autolock autoLock(mLock);
867 mDurationUs = durationUs;
868}
869
870void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t playingUs) {
871 Mutex::Autolock autoLock(mLock);
872 mPlayingTimeUs += playingUs;
873}
874
875void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t rebufferingUs) {
876 Mutex::Autolock autoLock(mLock);
877 mRebufferingTimeUs += rebufferingUs;
878 mRebufferingEvents++;
879}
880
881void NuPlayer2Driver::notifyRebufferingWhenExit(bool status) {
882 Mutex::Autolock autoLock(mLock);
883 mRebufferingAtExit = status;
884}
885
886void NuPlayer2Driver::notifySeekComplete() {
887 ALOGV("notifySeekComplete(%p)", this);
888 Mutex::Autolock autoLock(mLock);
889 mSeekInProgress = false;
890 notifySeekComplete_l();
891}
892
893void NuPlayer2Driver::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 ? MEDIA2_SEEK_COMPLETE : MEDIA2_PREPARED);
908}
909
910status_t NuPlayer2Driver::dump(
911 int fd, const Vector<String16> & /* args */) const {
912
913 Vector<sp<AMessage> > trackStats;
914 mPlayer->getStats(&trackStats);
915
916 AString logString(" NuPlayer2\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
Wei Jia12b9f4a2017-12-13 15:24:13 -0800987void NuPlayer2Driver::onMessageReceived(const sp<AMessage> &msg) {
988 switch (msg->what()) {
989 case kWhatNotifyListener: {
990 int32_t msgId;
Wei Jiac5c79da2017-12-21 18:03:05 -0800991 int32_t ext1 = 0;
992 int32_t ext2 = 0;
Wei Jia12b9f4a2017-12-13 15:24:13 -0800993 CHECK(msg->findInt32("messageId", &msgId));
Wei Jiac5c79da2017-12-21 18:03:05 -0800994 msg->findInt32("ext1", &ext1);
995 msg->findInt32("ext2", &ext2);
996 sp<ParcelWrapper> in;
997 sp<RefBase> obj;
998 if (msg->findObject("parcel", &obj) && obj != NULL) {
999 in = static_cast<ParcelWrapper *>(obj.get());
1000 }
1001 sendEvent(msgId, ext1, ext2, (in == NULL ? NULL : in->getParcel()));
Wei Jia12b9f4a2017-12-13 15:24:13 -08001002 break;
1003 }
1004 default:
1005 break;
1006 }
1007}
1008
Wei Jia53692fa2017-12-11 10:33:46 -08001009void NuPlayer2Driver::notifyListener(
1010 int msg, int ext1, int ext2, const Parcel *in) {
1011 Mutex::Autolock autoLock(mLock);
1012 notifyListener_l(msg, ext1, ext2, in);
1013}
1014
1015void NuPlayer2Driver::notifyListener_l(
1016 int msg, int ext1, int ext2, const Parcel *in) {
1017 ALOGD("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
1018 this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
1019 switch (msg) {
1020 case MEDIA2_PLAYBACK_COMPLETE:
1021 {
1022 if (mState != STATE_RESET_IN_PROGRESS) {
1023 if (mAutoLoop) {
1024 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
1025 if (mAudioSink != NULL) {
1026 streamType = mAudioSink->getAudioStreamType();
1027 }
1028 if (streamType == AUDIO_STREAM_NOTIFICATION) {
1029 ALOGW("disabling auto-loop for notification");
1030 mAutoLoop = false;
1031 }
1032 }
1033 if (mLooping || mAutoLoop) {
1034 mPlayer->seekToAsync(0);
1035 if (mAudioSink != NULL) {
1036 // The renderer has stopped the sink at the end in order to play out
1037 // the last little bit of audio. If we're looping, we need to restart it.
1038 mAudioSink->start();
1039 }
1040 // don't send completion event when looping
1041 return;
1042 }
1043 if (property_get_bool("persist.debug.sf.stats", false)) {
1044 Vector<String16> args;
1045 dump(-1, args);
1046 }
1047 mPlayer->pause();
1048 mState = STATE_PAUSED;
1049 }
1050 // fall through
1051 }
1052
1053 case MEDIA2_ERROR:
1054 {
1055 // when we have an error, add it to the analytics for this playback.
1056 // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
1057 // [test against msg is due to fall through from previous switch value]
1058 if (msg == MEDIA2_ERROR) {
1059 mAnalyticsItem->setInt32(kPlayerError, ext1);
1060 if (ext2 != 0) {
1061 mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
1062 }
Ray Essick51f4c872017-12-15 12:27:56 -08001063 mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
Wei Jia53692fa2017-12-11 10:33:46 -08001064 }
1065 mAtEOS = true;
1066 break;
1067 }
1068
1069 default:
1070 break;
1071 }
1072
Wei Jiac5c79da2017-12-21 18:03:05 -08001073 sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
1074 notify->setInt32("messageId", msg);
1075 notify->setInt32("ext1", ext1);
1076 notify->setInt32("ext2", ext2);
1077 notify->setObject("parcel", ParcelWrapper::Create(in));
1078 notify->post();
Wei Jia12b9f4a2017-12-13 15:24:13 -08001079}
1080
Wei Jia53692fa2017-12-11 10:33:46 -08001081void NuPlayer2Driver::notifySetDataSourceCompleted(status_t err) {
1082 Mutex::Autolock autoLock(mLock);
1083
1084 CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
1085
1086 mAsyncResult = err;
1087 mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
1088 mCondition.broadcast();
1089}
1090
1091void NuPlayer2Driver::notifyPrepareCompleted(status_t err) {
1092 ALOGV("notifyPrepareCompleted %d", err);
1093
1094 Mutex::Autolock autoLock(mLock);
1095
1096 if (mState != STATE_PREPARING) {
1097 // We were preparing asynchronously when the client called
1098 // reset(), we sent a premature "prepared" notification and
1099 // then initiated the reset. This notification is stale.
1100 CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
1101 return;
1102 }
1103
1104 CHECK_EQ(mState, STATE_PREPARING);
1105
1106 mAsyncResult = err;
1107
1108 if (err == OK) {
1109 // update state before notifying client, so that if client calls back into NuPlayer2Driver
1110 // in response, NuPlayer2Driver has the right state
1111 mState = STATE_PREPARED;
1112 if (mIsAsyncPrepare) {
1113 notifyListener_l(MEDIA2_PREPARED);
1114 }
1115 } else {
1116 mState = STATE_UNPREPARED;
1117 if (mIsAsyncPrepare) {
1118 notifyListener_l(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
1119 }
1120 }
1121
1122 sp<MetaData> meta = mPlayer->getFileMeta();
1123 int32_t loop;
1124 if (meta != NULL
1125 && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
1126 mAutoLoop = true;
1127 }
1128
1129 mCondition.broadcast();
1130}
1131
1132void NuPlayer2Driver::notifyFlagsChanged(uint32_t flags) {
1133 Mutex::Autolock autoLock(mLock);
1134
1135 mPlayerFlags = flags;
1136}
1137
1138// Modular DRM
1139status_t NuPlayer2Driver::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
1140{
1141 ALOGV("prepareDrm(%p) state: %d", this, mState);
1142
1143 // leaving the state verification for mediaplayer.cpp
1144 status_t ret = mPlayer->prepareDrm(uuid, drmSessionId);
1145
1146 ALOGV("prepareDrm ret: %d", ret);
1147
1148 return ret;
1149}
1150
1151status_t NuPlayer2Driver::releaseDrm()
1152{
1153 ALOGV("releaseDrm(%p) state: %d", this, mState);
1154
1155 // leaving the state verification for mediaplayer.cpp
1156 status_t ret = mPlayer->releaseDrm();
1157
1158 ALOGV("releaseDrm ret: %d", ret);
1159
1160 return ret;
1161}
1162
Ray Essick51f4c872017-12-15 12:27:56 -08001163std::string NuPlayer2Driver::stateString(State state) {
1164 const char *rval = NULL;
1165 char rawbuffer[16]; // allows "%d"
1166
1167 switch (state) {
1168 case STATE_IDLE: rval = "IDLE"; break;
1169 case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
1170 case STATE_UNPREPARED: rval = "UNPREPARED"; break;
1171 case STATE_PREPARING: rval = "PREPARING"; break;
1172 case STATE_PREPARED: rval = "PREPARED"; break;
1173 case STATE_RUNNING: rval = "RUNNING"; break;
1174 case STATE_PAUSED: rval = "PAUSED"; break;
1175 case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
1176 case STATE_STOPPED: rval = "STOPPED"; break;
1177 case STATE_STOPPED_AND_PREPARING: rval = "STOPPED_AND_PREPARING"; break;
1178 case STATE_STOPPED_AND_PREPARED: rval = "STOPPED_AND_PREPARED"; break;
1179 default:
1180 // yes, this buffer is shared and vulnerable to races
1181 snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
1182 rval = rawbuffer;
1183 break;
1184 }
1185
1186 return rval;
1187}
1188
Wei Jia53692fa2017-12-11 10:33:46 -08001189} // namespace android