blob: fd231a3ec7b48676428704181098052d4a98d864 [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
Wei Jiad2bb1bd2018-02-08 09:47:37 -080028#include <media/DataSourceDesc.h>
Wei Jia53692fa2017-12-11 10:33:46 -080029#include <media/stagefright/foundation/ADebug.h>
30#include <media/stagefright/foundation/ALooper.h>
31#include <media/stagefright/foundation/AUtils.h>
32#include <media/stagefright/foundation/ByteUtils.h>
33#include <media/stagefright/MediaClock.h>
34#include <media/stagefright/MetaData.h>
35#include <media/stagefright/Utils.h>
36
37#include <media/IMediaAnalyticsService.h>
38
Dongwon Kang9f631982018-07-10 12:34:41 -070039using google::protobuf::RepeatedPtrField;
40using android::media::MediaPlayer2Proto::Value;
41
Wei Jia53692fa2017-12-11 10:33:46 -080042static const int kDumpLockRetries = 50;
43static const int kDumpLockSleepUs = 20000;
44
45namespace android {
46
Wei Jiac5c79da2017-12-21 18:03:05 -080047struct ParcelWrapper : public RefBase {
48 static sp<ParcelWrapper> Create(const Parcel *p) {
49 if (p != NULL) {
50 sp<ParcelWrapper> pw = new ParcelWrapper();
51 if (pw->appendFrom(p) == OK) {
52 return pw;
53 }
54 }
55 return NULL;
56 }
57
58 const Parcel *getParcel() {
59 return mParcel;
60 }
61
62protected:
63 virtual ~ParcelWrapper() {
64 if (mParcel != NULL) {
65 delete mParcel;
66 }
67 }
68
69private:
70 ParcelWrapper()
71 : mParcel(NULL) { }
72
73 status_t appendFrom(const Parcel *p) {
74 if (mParcel == NULL) {
75 mParcel = new Parcel;
76 }
77 return mParcel->appendFrom(p, 0 /* start */, p->dataSize());
78 }
79
80 Parcel *mParcel;
81};
82
Wei Jia53692fa2017-12-11 10:33:46 -080083// key for media statistics
Ray Essickee54eef2018-01-24 11:16:54 -080084static const char *kKeyPlayer = "nuplayer";
Wei Jia53692fa2017-12-11 10:33:46 -080085// attrs for media statistics
Ray Essickde15b8c2018-01-30 16:35:56 -080086 // NB: these are matched with public Java API constants defined
87 // in frameworks/base/media/java/android/media/MediaPlayer2.java
88 // These must be kept synchronized with the constants there.
Wei Jia53692fa2017-12-11 10:33:46 -080089static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
90static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
91static const char *kPlayerWidth = "android.media.mediaplayer.width";
92static const char *kPlayerHeight = "android.media.mediaplayer.height";
93static const char *kPlayerFrames = "android.media.mediaplayer.frames";
94static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
95static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
96static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
97static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
98static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
99static const char *kPlayerError = "android.media.mediaplayer.err";
100static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
Ray Essickde15b8c2018-01-30 16:35:56 -0800101
102// NB: These are not yet exposed as public Java API constants.
Ray Essick51f4c872017-12-15 12:27:56 -0800103static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
Wei Jia53692fa2017-12-11 10:33:46 -0800104static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
105//
106static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
107static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
108static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
109
110
Wei Jia003fdb52018-02-06 14:44:32 -0800111NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid)
Wei Jia53692fa2017-12-11 10:33:46 -0800112 : mState(STATE_IDLE),
Wei Jia53692fa2017-12-11 10:33:46 -0800113 mAsyncResult(UNKNOWN_ERROR),
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800114 mSrcId(0),
Wei Jia53692fa2017-12-11 10:33:46 -0800115 mSetSurfaceInProgress(false),
116 mDurationUs(-1),
117 mPositionUs(-1),
118 mSeekInProgress(false),
119 mPlayingTimeUs(0),
120 mRebufferingTimeUs(0),
121 mRebufferingEvents(0),
122 mRebufferingAtExit(false),
123 mLooper(new ALooper),
Wei Jia12b9f4a2017-12-13 15:24:13 -0800124 mNuPlayer2Looper(new ALooper),
Wei Jia53692fa2017-12-11 10:33:46 -0800125 mMediaClock(new MediaClock),
Wei Jia003fdb52018-02-06 14:44:32 -0800126 mPlayer(new NuPlayer2(pid, uid, mMediaClock)),
Wei Jia53692fa2017-12-11 10:33:46 -0800127 mPlayerFlags(0),
128 mAnalyticsItem(NULL),
Wei Jia003fdb52018-02-06 14:44:32 -0800129 mClientUid(uid),
Wei Jia53692fa2017-12-11 10:33:46 -0800130 mAtEOS(false),
131 mLooping(false),
132 mAutoLoop(false) {
133 ALOGD("NuPlayer2Driver(%p) created, clientPid(%d)", this, pid);
134 mLooper->setName("NuPlayer2Driver Looper");
Wei Jia12b9f4a2017-12-13 15:24:13 -0800135 mNuPlayer2Looper->setName("NuPlayer2 Looper");
Wei Jia53692fa2017-12-11 10:33:46 -0800136
137 mMediaClock->init();
138
139 // set up an analytics record
140 mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
Wei Jia003fdb52018-02-06 14:44:32 -0800141 mAnalyticsItem->setUid(mClientUid);
Wei Jia53692fa2017-12-11 10:33:46 -0800142
Wei Jia12b9f4a2017-12-13 15:24:13 -0800143 mNuPlayer2Looper->start(
Wei Jia53692fa2017-12-11 10:33:46 -0800144 false, /* runOnCallingThread */
145 true, /* canCallJava */
146 PRIORITY_AUDIO);
147
Wei Jia12b9f4a2017-12-13 15:24:13 -0800148 mNuPlayer2Looper->registerHandler(mPlayer);
Wei Jia53692fa2017-12-11 10:33:46 -0800149
150 mPlayer->setDriver(this);
151}
152
153NuPlayer2Driver::~NuPlayer2Driver() {
154 ALOGV("~NuPlayer2Driver(%p)", this);
Wei Jia12b9f4a2017-12-13 15:24:13 -0800155 mNuPlayer2Looper->stop();
Wei Jia53692fa2017-12-11 10:33:46 -0800156 mLooper->stop();
157
158 // finalize any pending metrics, usually a no-op.
159 updateMetrics("destructor");
160 logMetrics("destructor");
161
162 if (mAnalyticsItem != NULL) {
163 delete mAnalyticsItem;
164 mAnalyticsItem = NULL;
165 }
166}
167
168status_t NuPlayer2Driver::initCheck() {
Wei Jia12b9f4a2017-12-13 15:24:13 -0800169 mLooper->start(
170 false, /* runOnCallingThread */
171 true, /* canCallJava */
172 PRIORITY_AUDIO);
173
174 mLooper->registerHandler(this);
Wei Jia53692fa2017-12-11 10:33:46 -0800175 return OK;
176}
177
Wei Jiac2636032018-02-01 09:15:25 -0800178status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
Wei Jia57aeffd2018-02-15 16:01:14 -0800179 ALOGV("setDataSource(%p)", this);
Wei Jia53692fa2017-12-11 10:33:46 -0800180 Mutex::Autolock autoLock(mLock);
181
182 if (mState != STATE_IDLE) {
183 return INVALID_OPERATION;
184 }
185
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800186 mSrcId = dsd->mId;
Wei Jia53692fa2017-12-11 10:33:46 -0800187 mState = STATE_SET_DATASOURCE_PENDING;
188
Wei Jiac2636032018-02-01 09:15:25 -0800189 mPlayer->setDataSourceAsync(dsd);
Wei Jia53692fa2017-12-11 10:33:46 -0800190
191 while (mState == STATE_SET_DATASOURCE_PENDING) {
192 mCondition.wait(mLock);
193 }
194
195 return mAsyncResult;
196}
197
Wei Jia57aeffd2018-02-15 16:01:14 -0800198status_t NuPlayer2Driver::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
199 ALOGV("prepareNextDataSource(%p)", this);
200 Mutex::Autolock autoLock(mLock);
201
202 mPlayer->prepareNextDataSourceAsync(dsd);
203
204 return OK;
205}
206
207status_t NuPlayer2Driver::playNextDataSource(int64_t srcId) {
208 ALOGV("playNextDataSource(%p)", this);
209 Mutex::Autolock autoLock(mLock);
210
211 mSrcId = srcId;
212 mPlayer->playNextDataSource(srcId);
213
214 return OK;
215}
216
Wei Jia28288fb2017-12-15 13:45:29 -0800217status_t NuPlayer2Driver::setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) {
Wei Jia53692fa2017-12-11 10:33:46 -0800218 ALOGV("setVideoSurfaceTexture(%p)", this);
219 Mutex::Autolock autoLock(mLock);
220
221 if (mSetSurfaceInProgress) {
222 return INVALID_OPERATION;
223 }
224
225 switch (mState) {
226 case STATE_SET_DATASOURCE_PENDING:
227 case STATE_RESET_IN_PROGRESS:
228 return INVALID_OPERATION;
229
230 default:
231 break;
232 }
233
234 mSetSurfaceInProgress = true;
235
Wei Jia28288fb2017-12-15 13:45:29 -0800236 mPlayer->setVideoSurfaceTextureAsync(nww);
Wei Jia53692fa2017-12-11 10:33:46 -0800237
238 while (mSetSurfaceInProgress) {
239 mCondition.wait(mLock);
240 }
241
242 return OK;
243}
244
245status_t NuPlayer2Driver::getBufferingSettings(BufferingSettings* buffering) {
246 ALOGV("getBufferingSettings(%p)", this);
247 {
248 Mutex::Autolock autoLock(mLock);
249 if (mState == STATE_IDLE) {
250 return INVALID_OPERATION;
251 }
252 }
253
254 return mPlayer->getBufferingSettings(buffering);
255}
256
257status_t NuPlayer2Driver::setBufferingSettings(const BufferingSettings& buffering) {
258 ALOGV("setBufferingSettings(%p)", this);
259 {
260 Mutex::Autolock autoLock(mLock);
261 if (mState == STATE_IDLE) {
262 return INVALID_OPERATION;
263 }
264 }
265
266 return mPlayer->setBufferingSettings(buffering);
267}
268
Wei Jia53692fa2017-12-11 10:33:46 -0800269status_t NuPlayer2Driver::prepareAsync() {
270 ALOGV("prepareAsync(%p)", this);
271 Mutex::Autolock autoLock(mLock);
272
273 switch (mState) {
274 case STATE_UNPREPARED:
275 mState = STATE_PREPARING;
Wei Jia53692fa2017-12-11 10:33:46 -0800276 mPlayer->prepareAsync();
277 return OK;
Wei Jia53692fa2017-12-11 10:33:46 -0800278 default:
279 return INVALID_OPERATION;
280 };
281}
282
283status_t NuPlayer2Driver::start() {
284 ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
285 Mutex::Autolock autoLock(mLock);
286 return start_l();
287}
288
289status_t NuPlayer2Driver::start_l() {
290 switch (mState) {
Wei Jia53692fa2017-12-11 10:33:46 -0800291 case STATE_PAUSED:
Wei Jia53692fa2017-12-11 10:33:46 -0800292 case STATE_PREPARED:
293 {
294 mPlayer->start();
295
296 // fall through
297 }
298
299 case STATE_RUNNING:
300 {
301 if (mAtEOS) {
302 mPlayer->seekToAsync(0);
303 mAtEOS = false;
304 mPositionUs = -1;
305 }
306 break;
307 }
308
309 default:
310 return INVALID_OPERATION;
311 }
312
313 mState = STATE_RUNNING;
314
315 return OK;
316}
317
Wei Jia53692fa2017-12-11 10:33:46 -0800318status_t NuPlayer2Driver::pause() {
319 ALOGD("pause(%p)", this);
320 // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
321 // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
322 // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
323 // getCurrentPosition here.
Wei Jia800fe372018-02-20 15:00:45 -0800324 int64_t unused;
Wei Jia53692fa2017-12-11 10:33:46 -0800325 getCurrentPosition(&unused);
326
327 Mutex::Autolock autoLock(mLock);
328
329 switch (mState) {
330 case STATE_PAUSED:
331 case STATE_PREPARED:
332 return OK;
333
334 case STATE_RUNNING:
335 mState = STATE_PAUSED;
Wei Jia53692fa2017-12-11 10:33:46 -0800336 mPlayer->pause();
337 break;
338
339 default:
340 return INVALID_OPERATION;
341 }
342
343 return OK;
344}
345
346bool NuPlayer2Driver::isPlaying() {
347 return mState == STATE_RUNNING && !mAtEOS;
348}
349
350status_t NuPlayer2Driver::setPlaybackSettings(const AudioPlaybackRate &rate) {
351 status_t err = mPlayer->setPlaybackSettings(rate);
352 if (err == OK) {
353 // try to update position
Wei Jia800fe372018-02-20 15:00:45 -0800354 int64_t unused;
Wei Jia53692fa2017-12-11 10:33:46 -0800355 getCurrentPosition(&unused);
356 Mutex::Autolock autoLock(mLock);
357 if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
358 mState = STATE_PAUSED;
Wei Jia53692fa2017-12-11 10:33:46 -0800359 } else if (rate.mSpeed != 0.f
360 && (mState == STATE_PAUSED
Wei Jia53692fa2017-12-11 10:33:46 -0800361 || mState == STATE_PREPARED)) {
362 err = start_l();
363 }
364 }
365 return err;
366}
367
368status_t NuPlayer2Driver::getPlaybackSettings(AudioPlaybackRate *rate) {
369 return mPlayer->getPlaybackSettings(rate);
370}
371
372status_t NuPlayer2Driver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
373 return mPlayer->setSyncSettings(sync, videoFpsHint);
374}
375
376status_t NuPlayer2Driver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
377 return mPlayer->getSyncSettings(sync, videoFps);
378}
379
Wei Jia800fe372018-02-20 15:00:45 -0800380status_t NuPlayer2Driver::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
381 ALOGD("seekTo(%p) (%lld ms, %d) at state %d", this, (long long)msec, mode, mState);
Wei Jia53692fa2017-12-11 10:33:46 -0800382 Mutex::Autolock autoLock(mLock);
383
384 int64_t seekTimeUs = msec * 1000ll;
385
386 switch (mState) {
387 case STATE_PREPARED:
Wei Jia53692fa2017-12-11 10:33:46 -0800388 case STATE_PAUSED:
389 case STATE_RUNNING:
390 {
391 mAtEOS = false;
392 mSeekInProgress = true;
Wei Jia53692fa2017-12-11 10:33:46 -0800393 mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
394 break;
395 }
396
397 default:
398 return INVALID_OPERATION;
399 }
400
401 mPositionUs = seekTimeUs;
402 return OK;
403}
404
Wei Jia800fe372018-02-20 15:00:45 -0800405status_t NuPlayer2Driver::getCurrentPosition(int64_t *msec) {
Wei Jia53692fa2017-12-11 10:33:46 -0800406 int64_t tempUs = 0;
407 {
408 Mutex::Autolock autoLock(mLock);
409 if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
410 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
Wei Jia800fe372018-02-20 15:00:45 -0800411 *msec = divRound(tempUs, (int64_t)(1000));
Wei Jia53692fa2017-12-11 10:33:46 -0800412 return OK;
413 }
414 }
415
416 status_t ret = mPlayer->getCurrentPosition(&tempUs);
417
418 Mutex::Autolock autoLock(mLock);
419 // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
420 // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
421 // position value that's different the seek to position.
422 if (ret != OK) {
423 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
424 } else {
425 mPositionUs = tempUs;
426 }
Wei Jia800fe372018-02-20 15:00:45 -0800427 *msec = divRound(tempUs, (int64_t)(1000));
Wei Jia53692fa2017-12-11 10:33:46 -0800428 return OK;
429}
430
Wei Jia800fe372018-02-20 15:00:45 -0800431status_t NuPlayer2Driver::getDuration(int64_t *msec) {
Wei Jia53692fa2017-12-11 10:33:46 -0800432 Mutex::Autolock autoLock(mLock);
433
434 if (mDurationUs < 0) {
435 return UNKNOWN_ERROR;
436 }
437
438 *msec = (mDurationUs + 500ll) / 1000;
439
440 return OK;
441}
442
443void NuPlayer2Driver::updateMetrics(const char *where) {
444 if (where == NULL) {
445 where = "unknown";
446 }
447 ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
448
449 // gather the final stats for this record
450 Vector<sp<AMessage>> trackStats;
451 mPlayer->getStats(&trackStats);
452
453 if (trackStats.size() > 0) {
454 for (size_t i = 0; i < trackStats.size(); ++i) {
455 const sp<AMessage> &stats = trackStats.itemAt(i);
456
457 AString mime;
458 stats->findString("mime", &mime);
459
460 AString name;
461 stats->findString("component-name", &name);
462
463 if (mime.startsWith("video/")) {
464 int32_t width, height;
465 mAnalyticsItem->setCString(kPlayerVMime, mime.c_str());
466 if (!name.empty()) {
467 mAnalyticsItem->setCString(kPlayerVCodec, name.c_str());
468 }
469
470 if (stats->findInt32("width", &width)
471 && stats->findInt32("height", &height)) {
472 mAnalyticsItem->setInt32(kPlayerWidth, width);
473 mAnalyticsItem->setInt32(kPlayerHeight, height);
474 }
475
476 int64_t numFramesTotal = 0;
477 int64_t numFramesDropped = 0;
478 stats->findInt64("frames-total", &numFramesTotal);
479 stats->findInt64("frames-dropped-output", &numFramesDropped);
480
481 mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal);
482 mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
483
484
485 } else if (mime.startsWith("audio/")) {
486 mAnalyticsItem->setCString(kPlayerAMime, mime.c_str());
487 if (!name.empty()) {
488 mAnalyticsItem->setCString(kPlayerACodec, name.c_str());
489 }
490 }
491 }
492 }
493
494 // always provide duration and playing time, even if they have 0/unknown values.
495
496 // getDuration() uses mLock for mutex -- careful where we use it.
Wei Jia800fe372018-02-20 15:00:45 -0800497 int64_t duration_ms = -1;
Wei Jia53692fa2017-12-11 10:33:46 -0800498 getDuration(&duration_ms);
499 mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
500
501 mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
502
503 if (mRebufferingEvents != 0) {
504 mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
505 mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
506 mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
507 }
508
509 mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
510}
511
512
513void NuPlayer2Driver::logMetrics(const char *where) {
514 if (where == NULL) {
515 where = "unknown";
516 }
517 ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
518
519 if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
520 return;
521 }
522
523 // log only non-empty records
524 // we always updateMetrics() before we get here
525 // and that always injects 3 fields (duration, playing time, and
526 // datasource) into the record.
527 // So the canonical "empty" record has 3 elements in it.
528 if (mAnalyticsItem->count() > 3) {
529
Wei Jia53692fa2017-12-11 10:33:46 -0800530 mAnalyticsItem->selfrecord();
531
532 // re-init in case we prepare() and start() again.
533 delete mAnalyticsItem ;
Ray Essickee54eef2018-01-24 11:16:54 -0800534 mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
Wei Jia53692fa2017-12-11 10:33:46 -0800535 if (mAnalyticsItem) {
Wei Jia53692fa2017-12-11 10:33:46 -0800536 mAnalyticsItem->setUid(mClientUid);
537 }
538 } else {
539 ALOGV("did not have anything to record");
540 }
541}
542
543status_t NuPlayer2Driver::reset() {
544 ALOGD("reset(%p) at state %d", this, mState);
545
546 updateMetrics("reset");
547 logMetrics("reset");
548
549 Mutex::Autolock autoLock(mLock);
550
551 switch (mState) {
552 case STATE_IDLE:
553 return OK;
554
555 case STATE_SET_DATASOURCE_PENDING:
556 case STATE_RESET_IN_PROGRESS:
557 return INVALID_OPERATION;
558
559 case STATE_PREPARING:
560 {
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800561 notifyListener_l(mSrcId, MEDIA2_PREPARED);
Wei Jia53692fa2017-12-11 10:33:46 -0800562 break;
563 }
564
565 default:
566 break;
567 }
568
Wei Jia53692fa2017-12-11 10:33:46 -0800569 mState = STATE_RESET_IN_PROGRESS;
570 mPlayer->resetAsync();
571
572 while (mState == STATE_RESET_IN_PROGRESS) {
573 mCondition.wait(mLock);
574 }
575
576 mDurationUs = -1;
577 mPositionUs = -1;
578 mLooping = false;
579 mPlayingTimeUs = 0;
580 mRebufferingTimeUs = 0;
581 mRebufferingEvents = 0;
582 mRebufferingAtExit = false;
583
584 return OK;
585}
586
587status_t NuPlayer2Driver::notifyAt(int64_t mediaTimeUs) {
588 ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
589 return mPlayer->notifyAt(mediaTimeUs);
590}
591
592status_t NuPlayer2Driver::setLooping(int loop) {
593 mLooping = loop != 0;
594 return OK;
595}
596
Dongwon Kang9f631982018-07-10 12:34:41 -0700597status_t NuPlayer2Driver::invoke(const PlayerMessage &request, PlayerMessage *response) {
598 if (response == NULL) {
Wei Jia53692fa2017-12-11 10:33:46 -0800599 ALOGE("reply is a NULL pointer");
600 return BAD_VALUE;
601 }
602
Dongwon Kang9f631982018-07-10 12:34:41 -0700603 RepeatedPtrField<const Value>::const_iterator it = request.values().cbegin();
604 int32_t methodId = (it++)->int32_value();
Wei Jia53692fa2017-12-11 10:33:46 -0800605
606 switch (methodId) {
607 case MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE:
608 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700609 int mode = (it++)->int32_value();
Wei Jia53692fa2017-12-11 10:33:46 -0800610 return mPlayer->setVideoScalingMode(mode);
611 }
612
613 case MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO:
614 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700615 return mPlayer->getTrackInfo(response);
Wei Jia53692fa2017-12-11 10:33:46 -0800616 }
617
618 case MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK:
619 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700620 int trackIndex = (it++)->int32_value();
Wei Jia800fe372018-02-20 15:00:45 -0800621 int64_t msec = 0;
Wei Jia53692fa2017-12-11 10:33:46 -0800622 // getCurrentPosition should always return OK
623 getCurrentPosition(&msec);
624 return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll);
625 }
626
627 case MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK:
628 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700629 int trackIndex = (it++)->int32_value();
Wei Jia53692fa2017-12-11 10:33:46 -0800630 return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
631 }
632
633 case MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK:
634 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700635 int32_t type = (it++)->int32_value();
636 return mPlayer->getSelectedTrack(type, response);
Wei Jia53692fa2017-12-11 10:33:46 -0800637 }
638
639 default:
640 {
641 return INVALID_OPERATION;
642 }
643 }
644}
645
646void NuPlayer2Driver::setAudioSink(const sp<AudioSink> &audioSink) {
647 mPlayer->setAudioSink(audioSink);
648 mAudioSink = audioSink;
649}
650
651status_t NuPlayer2Driver::setParameter(
652 int /* key */, const Parcel & /* request */) {
653 return INVALID_OPERATION;
654}
655
656status_t NuPlayer2Driver::getParameter(int key, Parcel *reply) {
657
658 if (key == FOURCC('m','t','r','X')) {
659 // mtrX -- a play on 'metrics' (not matrix)
660 // gather current info all together, parcel it, and send it back
661 updateMetrics("api");
662 mAnalyticsItem->writeToParcel(reply);
663 return OK;
664 }
665
666 return INVALID_OPERATION;
667}
668
669status_t NuPlayer2Driver::getMetadata(
670 const media::Metadata::Filter& /* ids */, Parcel *records) {
671 Mutex::Autolock autoLock(mLock);
672
673 using media::Metadata;
674
675 Metadata meta(records);
676
677 meta.appendBool(
678 Metadata::kPauseAvailable,
679 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_PAUSE);
680
681 meta.appendBool(
682 Metadata::kSeekBackwardAvailable,
683 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK_BACKWARD);
684
685 meta.appendBool(
686 Metadata::kSeekForwardAvailable,
687 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK_FORWARD);
688
689 meta.appendBool(
690 Metadata::kSeekAvailable,
691 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK);
692
693 return OK;
694}
695
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800696void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
Wei Jia53692fa2017-12-11 10:33:46 -0800697 ALOGD("notifyResetComplete(%p)", this);
698 Mutex::Autolock autoLock(mLock);
699
700 CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
701 mState = STATE_IDLE;
702 mCondition.broadcast();
703}
704
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800705void NuPlayer2Driver::notifySetSurfaceComplete(int64_t /* srcId */) {
Wei Jia53692fa2017-12-11 10:33:46 -0800706 ALOGV("notifySetSurfaceComplete(%p)", this);
707 Mutex::Autolock autoLock(mLock);
708
709 CHECK(mSetSurfaceInProgress);
710 mSetSurfaceInProgress = false;
711
712 mCondition.broadcast();
713}
714
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800715void NuPlayer2Driver::notifyDuration(int64_t /* srcId */, int64_t durationUs) {
Wei Jia53692fa2017-12-11 10:33:46 -0800716 Mutex::Autolock autoLock(mLock);
717 mDurationUs = durationUs;
718}
719
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800720void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t /* srcId */, int64_t playingUs) {
Wei Jia53692fa2017-12-11 10:33:46 -0800721 Mutex::Autolock autoLock(mLock);
722 mPlayingTimeUs += playingUs;
723}
724
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800725void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t /* srcId */, int64_t rebufferingUs) {
Wei Jia53692fa2017-12-11 10:33:46 -0800726 Mutex::Autolock autoLock(mLock);
727 mRebufferingTimeUs += rebufferingUs;
728 mRebufferingEvents++;
729}
730
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800731void NuPlayer2Driver::notifyRebufferingWhenExit(int64_t /* srcId */, bool status) {
Wei Jia53692fa2017-12-11 10:33:46 -0800732 Mutex::Autolock autoLock(mLock);
733 mRebufferingAtExit = status;
734}
735
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800736void NuPlayer2Driver::notifySeekComplete(int64_t srcId) {
Wei Jia53692fa2017-12-11 10:33:46 -0800737 ALOGV("notifySeekComplete(%p)", this);
738 Mutex::Autolock autoLock(mLock);
739 mSeekInProgress = false;
Wei Jia0151ef42018-08-24 16:40:21 -0700740 notifyListener_l(srcId, MEDIA2_SEEK_COMPLETE);
Wei Jia53692fa2017-12-11 10:33:46 -0800741}
742
743status_t NuPlayer2Driver::dump(
744 int fd, const Vector<String16> & /* args */) const {
745
746 Vector<sp<AMessage> > trackStats;
747 mPlayer->getStats(&trackStats);
748
749 AString logString(" NuPlayer2\n");
750 char buf[256] = {0};
751
752 bool locked = false;
753 for (int i = 0; i < kDumpLockRetries; ++i) {
754 if (mLock.tryLock() == NO_ERROR) {
755 locked = true;
756 break;
757 }
758 usleep(kDumpLockSleepUs);
759 }
760
761 if (locked) {
762 snprintf(buf, sizeof(buf), " state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
763 mState, mAtEOS, mLooping, mAutoLoop);
764 mLock.unlock();
765 } else {
766 snprintf(buf, sizeof(buf), " NPD(%p) lock is taken\n", this);
767 }
768 logString.append(buf);
769
770 for (size_t i = 0; i < trackStats.size(); ++i) {
771 const sp<AMessage> &stats = trackStats.itemAt(i);
772
773 AString mime;
774 if (stats->findString("mime", &mime)) {
775 snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str());
776 logString.append(buf);
777 }
778
779 AString name;
780 if (stats->findString("component-name", &name)) {
781 snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str());
782 logString.append(buf);
783 }
784
785 if (mime.startsWith("video/")) {
786 int32_t width, height;
787 if (stats->findInt32("width", &width)
788 && stats->findInt32("height", &height)) {
789 snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height);
790 logString.append(buf);
791 }
792
793 int64_t numFramesTotal = 0;
794 int64_t numFramesDropped = 0;
795
796 stats->findInt64("frames-total", &numFramesTotal);
797 stats->findInt64("frames-dropped-output", &numFramesDropped);
798 snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), "
799 "percentageDropped(%.2f%%)\n",
800 (long long)numFramesTotal,
801 (long long)numFramesDropped,
802 numFramesTotal == 0
803 ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
804 logString.append(buf);
805 }
806 }
807
808 ALOGI("%s", logString.c_str());
809
810 if (fd >= 0) {
811 FILE *out = fdopen(dup(fd), "w");
812 fprintf(out, "%s", logString.c_str());
813 fclose(out);
814 out = NULL;
815 }
816
817 return OK;
818}
819
Wei Jia12b9f4a2017-12-13 15:24:13 -0800820void NuPlayer2Driver::onMessageReceived(const sp<AMessage> &msg) {
821 switch (msg->what()) {
822 case kWhatNotifyListener: {
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800823 int64_t srcId;
Wei Jia12b9f4a2017-12-13 15:24:13 -0800824 int32_t msgId;
Wei Jiac5c79da2017-12-21 18:03:05 -0800825 int32_t ext1 = 0;
826 int32_t ext2 = 0;
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800827 CHECK(msg->findInt64("srcId", &srcId));
Wei Jia12b9f4a2017-12-13 15:24:13 -0800828 CHECK(msg->findInt32("messageId", &msgId));
Wei Jiac5c79da2017-12-21 18:03:05 -0800829 msg->findInt32("ext1", &ext1);
830 msg->findInt32("ext2", &ext2);
831 sp<ParcelWrapper> in;
832 sp<RefBase> obj;
833 if (msg->findObject("parcel", &obj) && obj != NULL) {
834 in = static_cast<ParcelWrapper *>(obj.get());
835 }
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800836 sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getParcel()));
Wei Jia12b9f4a2017-12-13 15:24:13 -0800837 break;
838 }
839 default:
840 break;
841 }
842}
843
Wei Jia53692fa2017-12-11 10:33:46 -0800844void NuPlayer2Driver::notifyListener(
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800845 int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
Wei Jia53692fa2017-12-11 10:33:46 -0800846 Mutex::Autolock autoLock(mLock);
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800847 notifyListener_l(srcId, msg, ext1, ext2, in);
Wei Jia53692fa2017-12-11 10:33:46 -0800848}
849
850void NuPlayer2Driver::notifyListener_l(
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800851 int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
852 ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
853 this, (long long)srcId, msg, ext1, ext2,
854 (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
Wei Jia57aeffd2018-02-15 16:01:14 -0800855 if (srcId == mSrcId) {
856 switch (msg) {
857 case MEDIA2_PLAYBACK_COMPLETE:
858 {
859 if (mState != STATE_RESET_IN_PROGRESS) {
860 if (mAutoLoop) {
861 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
862 if (mAudioSink != NULL) {
863 streamType = mAudioSink->getAudioStreamType();
864 }
865 if (streamType == AUDIO_STREAM_NOTIFICATION) {
866 ALOGW("disabling auto-loop for notification");
867 mAutoLoop = false;
868 }
Wei Jia53692fa2017-12-11 10:33:46 -0800869 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800870 if (mLooping || mAutoLoop) {
871 mPlayer->seekToAsync(0);
872 if (mAudioSink != NULL) {
873 // The renderer has stopped the sink at the end in order to play out
874 // the last little bit of audio. In looping mode, we need to restart it.
875 mAudioSink->start();
876 }
Wei Jia9af566a2018-08-10 16:36:35 -0700877
878 sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
879 notify->setInt64("srcId", srcId);
880 notify->setInt32("messageId", MEDIA2_INFO);
881 notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
882 notify->post();
Wei Jia57aeffd2018-02-15 16:01:14 -0800883 return;
Wei Jia53692fa2017-12-11 10:33:46 -0800884 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800885 if (property_get_bool("persist.debug.sf.stats", false)) {
886 Vector<String16> args;
887 dump(-1, args);
Wei Jia53692fa2017-12-11 10:33:46 -0800888 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800889 mPlayer->pause();
890 mState = STATE_PAUSED;
Wei Jia53692fa2017-12-11 10:33:46 -0800891 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800892 // fall through
Wei Jia53692fa2017-12-11 10:33:46 -0800893 }
Wei Jia53692fa2017-12-11 10:33:46 -0800894
Wei Jia57aeffd2018-02-15 16:01:14 -0800895 case MEDIA2_ERROR:
896 {
897 // when we have an error, add it to the analytics for this playback.
898 // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
899 // [test against msg is due to fall through from previous switch value]
900 if (msg == MEDIA2_ERROR) {
901 mAnalyticsItem->setInt32(kPlayerError, ext1);
902 if (ext2 != 0) {
903 mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
904 }
905 mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
Wei Jia53692fa2017-12-11 10:33:46 -0800906 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800907 mAtEOS = true;
908 break;
Wei Jia53692fa2017-12-11 10:33:46 -0800909 }
Wei Jia53692fa2017-12-11 10:33:46 -0800910
Wei Jia57aeffd2018-02-15 16:01:14 -0800911 default:
912 break;
913 }
Wei Jia53692fa2017-12-11 10:33:46 -0800914 }
915
Wei Jiac5c79da2017-12-21 18:03:05 -0800916 sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800917 notify->setInt64("srcId", srcId);
Wei Jiac5c79da2017-12-21 18:03:05 -0800918 notify->setInt32("messageId", msg);
919 notify->setInt32("ext1", ext1);
920 notify->setInt32("ext2", ext2);
921 notify->setObject("parcel", ParcelWrapper::Create(in));
922 notify->post();
Wei Jia12b9f4a2017-12-13 15:24:13 -0800923}
924
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800925void NuPlayer2Driver::notifySetDataSourceCompleted(int64_t /* srcId */, status_t err) {
Wei Jia53692fa2017-12-11 10:33:46 -0800926 Mutex::Autolock autoLock(mLock);
927
928 CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
929
930 mAsyncResult = err;
931 mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
932 mCondition.broadcast();
933}
934
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800935void NuPlayer2Driver::notifyPrepareCompleted(int64_t srcId, status_t err) {
Wei Jia53692fa2017-12-11 10:33:46 -0800936 ALOGV("notifyPrepareCompleted %d", err);
937
938 Mutex::Autolock autoLock(mLock);
939
Wei Jia57aeffd2018-02-15 16:01:14 -0800940 if (srcId != mSrcId) {
941 if (err == OK) {
942 notifyListener_l(srcId, MEDIA2_PREPARED);
943 } else {
944 notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
945 }
946 return;
947 }
948
Wei Jia53692fa2017-12-11 10:33:46 -0800949 if (mState != STATE_PREPARING) {
950 // We were preparing asynchronously when the client called
951 // reset(), we sent a premature "prepared" notification and
952 // then initiated the reset. This notification is stale.
953 CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
954 return;
955 }
956
957 CHECK_EQ(mState, STATE_PREPARING);
958
959 mAsyncResult = err;
960
961 if (err == OK) {
962 // update state before notifying client, so that if client calls back into NuPlayer2Driver
963 // in response, NuPlayer2Driver has the right state
964 mState = STATE_PREPARED;
Wei Jia57aeffd2018-02-15 16:01:14 -0800965 notifyListener_l(srcId, MEDIA2_PREPARED);
Wei Jia53692fa2017-12-11 10:33:46 -0800966 } else {
967 mState = STATE_UNPREPARED;
Wei Jia57aeffd2018-02-15 16:01:14 -0800968 notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
Wei Jia53692fa2017-12-11 10:33:46 -0800969 }
970
971 sp<MetaData> meta = mPlayer->getFileMeta();
972 int32_t loop;
973 if (meta != NULL
974 && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
975 mAutoLoop = true;
976 }
977
978 mCondition.broadcast();
979}
980
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800981void NuPlayer2Driver::notifyFlagsChanged(int64_t /* srcId */, uint32_t flags) {
Wei Jia53692fa2017-12-11 10:33:46 -0800982 Mutex::Autolock autoLock(mLock);
983
984 mPlayerFlags = flags;
985}
986
987// Modular DRM
988status_t NuPlayer2Driver::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
989{
990 ALOGV("prepareDrm(%p) state: %d", this, mState);
991
992 // leaving the state verification for mediaplayer.cpp
993 status_t ret = mPlayer->prepareDrm(uuid, drmSessionId);
994
995 ALOGV("prepareDrm ret: %d", ret);
996
997 return ret;
998}
999
1000status_t NuPlayer2Driver::releaseDrm()
1001{
1002 ALOGV("releaseDrm(%p) state: %d", this, mState);
1003
1004 // leaving the state verification for mediaplayer.cpp
1005 status_t ret = mPlayer->releaseDrm();
1006
1007 ALOGV("releaseDrm ret: %d", ret);
1008
1009 return ret;
1010}
1011
Ray Essick51f4c872017-12-15 12:27:56 -08001012std::string NuPlayer2Driver::stateString(State state) {
1013 const char *rval = NULL;
1014 char rawbuffer[16]; // allows "%d"
1015
1016 switch (state) {
1017 case STATE_IDLE: rval = "IDLE"; break;
1018 case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
1019 case STATE_UNPREPARED: rval = "UNPREPARED"; break;
1020 case STATE_PREPARING: rval = "PREPARING"; break;
1021 case STATE_PREPARED: rval = "PREPARED"; break;
1022 case STATE_RUNNING: rval = "RUNNING"; break;
1023 case STATE_PAUSED: rval = "PAUSED"; break;
1024 case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
Ray Essick51f4c872017-12-15 12:27:56 -08001025 default:
1026 // yes, this buffer is shared and vulnerable to races
1027 snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
1028 rval = rawbuffer;
1029 break;
1030 }
1031
1032 return rval;
1033}
1034
Wei Jia53692fa2017-12-11 10:33:46 -08001035} // namespace android