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