blob: d29a0123aaab6587a87481d12b21e02bdd02f499 [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
Dongwon Kang41929fb2018-09-09 08:29:56 -070047struct PlayerMessageWrapper : public RefBase {
48 static sp<PlayerMessageWrapper> Create(const PlayerMessage *p) {
Wei Jiac5c79da2017-12-21 18:03:05 -080049 if (p != NULL) {
Dongwon Kang41929fb2018-09-09 08:29:56 -070050 sp<PlayerMessageWrapper> pw = new PlayerMessageWrapper();
51 pw->copyFrom(p);
52 return pw;
Wei Jiac5c79da2017-12-21 18:03:05 -080053 }
54 return NULL;
55 }
56
Dongwon Kang41929fb2018-09-09 08:29:56 -070057 const PlayerMessage *getPlayerMessage() {
58 return mPlayerMessage;
Wei Jiac5c79da2017-12-21 18:03:05 -080059 }
60
61protected:
Dongwon Kang41929fb2018-09-09 08:29:56 -070062 virtual ~PlayerMessageWrapper() {
63 if (mPlayerMessage != NULL) {
64 delete mPlayerMessage;
Wei Jiac5c79da2017-12-21 18:03:05 -080065 }
66 }
67
68private:
Dongwon Kang41929fb2018-09-09 08:29:56 -070069 PlayerMessageWrapper()
70 : mPlayerMessage(NULL) { }
Wei Jiac5c79da2017-12-21 18:03:05 -080071
Dongwon Kang41929fb2018-09-09 08:29:56 -070072 void copyFrom(const PlayerMessage *p) {
73 if (mPlayerMessage == NULL) {
74 mPlayerMessage = new PlayerMessage;
Wei Jiac5c79da2017-12-21 18:03:05 -080075 }
Dongwon Kang41929fb2018-09-09 08:29:56 -070076 mPlayerMessage->CopyFrom(*p);
Wei Jiac5c79da2017-12-21 18:03:05 -080077 }
78
Dongwon Kang41929fb2018-09-09 08:29:56 -070079 PlayerMessage *mPlayerMessage;
Wei Jiac5c79da2017-12-21 18:03:05 -080080};
81
Wei Jia53692fa2017-12-11 10:33:46 -080082// key for media statistics
Ray Essickee54eef2018-01-24 11:16:54 -080083static const char *kKeyPlayer = "nuplayer";
Wei Jia53692fa2017-12-11 10:33:46 -080084// attrs for media statistics
Ray Essickde15b8c2018-01-30 16:35:56 -080085 // NB: these are matched with public Java API constants defined
86 // in frameworks/base/media/java/android/media/MediaPlayer2.java
87 // These must be kept synchronized with the constants there.
Wei Jia53692fa2017-12-11 10:33:46 -080088static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
89static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
90static const char *kPlayerWidth = "android.media.mediaplayer.width";
91static const char *kPlayerHeight = "android.media.mediaplayer.height";
92static const char *kPlayerFrames = "android.media.mediaplayer.frames";
93static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
94static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
95static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
96static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
97static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
98static const char *kPlayerError = "android.media.mediaplayer.err";
99static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
Ray Essickde15b8c2018-01-30 16:35:56 -0800100
101// NB: These are not yet exposed as public Java API constants.
Ray Essick51f4c872017-12-15 12:27:56 -0800102static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
Wei Jia53692fa2017-12-11 10:33:46 -0800103static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
104//
105static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
106static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
107static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
108
109
Wei Jia003fdb52018-02-06 14:44:32 -0800110NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid)
Wei Jia53692fa2017-12-11 10:33:46 -0800111 : mState(STATE_IDLE),
Wei Jia53692fa2017-12-11 10:33:46 -0800112 mAsyncResult(UNKNOWN_ERROR),
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800113 mSrcId(0),
Wei Jia53692fa2017-12-11 10:33:46 -0800114 mSetSurfaceInProgress(false),
115 mDurationUs(-1),
116 mPositionUs(-1),
117 mSeekInProgress(false),
118 mPlayingTimeUs(0),
119 mRebufferingTimeUs(0),
120 mRebufferingEvents(0),
121 mRebufferingAtExit(false),
122 mLooper(new ALooper),
Wei Jia12b9f4a2017-12-13 15:24:13 -0800123 mNuPlayer2Looper(new ALooper),
Wei Jia53692fa2017-12-11 10:33:46 -0800124 mMediaClock(new MediaClock),
Wei Jia003fdb52018-02-06 14:44:32 -0800125 mPlayer(new NuPlayer2(pid, uid, mMediaClock)),
Wei Jia53692fa2017-12-11 10:33:46 -0800126 mPlayerFlags(0),
127 mAnalyticsItem(NULL),
Wei Jia003fdb52018-02-06 14:44:32 -0800128 mClientUid(uid),
Wei Jia53692fa2017-12-11 10:33:46 -0800129 mAtEOS(false),
130 mLooping(false),
131 mAutoLoop(false) {
132 ALOGD("NuPlayer2Driver(%p) created, clientPid(%d)", this, pid);
133 mLooper->setName("NuPlayer2Driver Looper");
Wei Jia12b9f4a2017-12-13 15:24:13 -0800134 mNuPlayer2Looper->setName("NuPlayer2 Looper");
Wei Jia53692fa2017-12-11 10:33:46 -0800135
136 mMediaClock->init();
137
138 // set up an analytics record
139 mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
Wei Jia003fdb52018-02-06 14:44:32 -0800140 mAnalyticsItem->setUid(mClientUid);
Wei Jia53692fa2017-12-11 10:33:46 -0800141
Wei Jia12b9f4a2017-12-13 15:24:13 -0800142 mNuPlayer2Looper->start(
Wei Jia53692fa2017-12-11 10:33:46 -0800143 false, /* runOnCallingThread */
144 true, /* canCallJava */
145 PRIORITY_AUDIO);
146
Wei Jia12b9f4a2017-12-13 15:24:13 -0800147 mNuPlayer2Looper->registerHandler(mPlayer);
Wei Jia53692fa2017-12-11 10:33:46 -0800148
149 mPlayer->setDriver(this);
150}
151
152NuPlayer2Driver::~NuPlayer2Driver() {
153 ALOGV("~NuPlayer2Driver(%p)", this);
Wei Jia12b9f4a2017-12-13 15:24:13 -0800154 mNuPlayer2Looper->stop();
Wei Jia53692fa2017-12-11 10:33:46 -0800155 mLooper->stop();
156
157 // finalize any pending metrics, usually a no-op.
158 updateMetrics("destructor");
159 logMetrics("destructor");
160
161 if (mAnalyticsItem != NULL) {
162 delete mAnalyticsItem;
163 mAnalyticsItem = NULL;
164 }
165}
166
167status_t NuPlayer2Driver::initCheck() {
Wei Jia12b9f4a2017-12-13 15:24:13 -0800168 mLooper->start(
169 false, /* runOnCallingThread */
170 true, /* canCallJava */
171 PRIORITY_AUDIO);
172
173 mLooper->registerHandler(this);
Wei Jia53692fa2017-12-11 10:33:46 -0800174 return OK;
175}
176
Wei Jiac2636032018-02-01 09:15:25 -0800177status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
Wei Jia57aeffd2018-02-15 16:01:14 -0800178 ALOGV("setDataSource(%p)", this);
Wei Jia53692fa2017-12-11 10:33:46 -0800179 Mutex::Autolock autoLock(mLock);
180
181 if (mState != STATE_IDLE) {
182 return INVALID_OPERATION;
183 }
184
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800185 mSrcId = dsd->mId;
Wei Jia53692fa2017-12-11 10:33:46 -0800186 mState = STATE_SET_DATASOURCE_PENDING;
187
Wei Jiac2636032018-02-01 09:15:25 -0800188 mPlayer->setDataSourceAsync(dsd);
Wei Jia53692fa2017-12-11 10:33:46 -0800189
190 while (mState == STATE_SET_DATASOURCE_PENDING) {
191 mCondition.wait(mLock);
192 }
193
194 return mAsyncResult;
195}
196
Wei Jia57aeffd2018-02-15 16:01:14 -0800197status_t NuPlayer2Driver::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
198 ALOGV("prepareNextDataSource(%p)", this);
199 Mutex::Autolock autoLock(mLock);
200
201 mPlayer->prepareNextDataSourceAsync(dsd);
202
203 return OK;
204}
205
206status_t NuPlayer2Driver::playNextDataSource(int64_t srcId) {
207 ALOGV("playNextDataSource(%p)", this);
208 Mutex::Autolock autoLock(mLock);
209
210 mSrcId = srcId;
211 mPlayer->playNextDataSource(srcId);
212
213 return OK;
214}
215
Wei Jia28288fb2017-12-15 13:45:29 -0800216status_t NuPlayer2Driver::setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) {
Wei Jia53692fa2017-12-11 10:33:46 -0800217 ALOGV("setVideoSurfaceTexture(%p)", this);
218 Mutex::Autolock autoLock(mLock);
219
220 if (mSetSurfaceInProgress) {
221 return INVALID_OPERATION;
222 }
223
224 switch (mState) {
225 case STATE_SET_DATASOURCE_PENDING:
226 case STATE_RESET_IN_PROGRESS:
227 return INVALID_OPERATION;
228
229 default:
230 break;
231 }
232
233 mSetSurfaceInProgress = true;
234
Wei Jia28288fb2017-12-15 13:45:29 -0800235 mPlayer->setVideoSurfaceTextureAsync(nww);
Wei Jia53692fa2017-12-11 10:33:46 -0800236
237 while (mSetSurfaceInProgress) {
238 mCondition.wait(mLock);
239 }
240
241 return OK;
242}
243
244status_t NuPlayer2Driver::getBufferingSettings(BufferingSettings* buffering) {
245 ALOGV("getBufferingSettings(%p)", this);
246 {
247 Mutex::Autolock autoLock(mLock);
248 if (mState == STATE_IDLE) {
249 return INVALID_OPERATION;
250 }
251 }
252
253 return mPlayer->getBufferingSettings(buffering);
254}
255
256status_t NuPlayer2Driver::setBufferingSettings(const BufferingSettings& buffering) {
257 ALOGV("setBufferingSettings(%p)", this);
258 {
259 Mutex::Autolock autoLock(mLock);
260 if (mState == STATE_IDLE) {
261 return INVALID_OPERATION;
262 }
263 }
264
265 return mPlayer->setBufferingSettings(buffering);
266}
267
Wei Jia53692fa2017-12-11 10:33:46 -0800268status_t NuPlayer2Driver::prepareAsync() {
269 ALOGV("prepareAsync(%p)", this);
270 Mutex::Autolock autoLock(mLock);
271
272 switch (mState) {
273 case STATE_UNPREPARED:
274 mState = STATE_PREPARING;
Wei Jia53692fa2017-12-11 10:33:46 -0800275 mPlayer->prepareAsync();
276 return OK;
Wei Jia53692fa2017-12-11 10:33:46 -0800277 default:
278 return INVALID_OPERATION;
279 };
280}
281
282status_t NuPlayer2Driver::start() {
283 ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
284 Mutex::Autolock autoLock(mLock);
285 return start_l();
286}
287
288status_t NuPlayer2Driver::start_l() {
289 switch (mState) {
Wei Jia53692fa2017-12-11 10:33:46 -0800290 case STATE_PAUSED:
Wei Jia53692fa2017-12-11 10:33:46 -0800291 case STATE_PREPARED:
292 {
293 mPlayer->start();
294
295 // fall through
296 }
297
298 case STATE_RUNNING:
299 {
300 if (mAtEOS) {
301 mPlayer->seekToAsync(0);
302 mAtEOS = false;
303 mPositionUs = -1;
304 }
305 break;
306 }
307
308 default:
309 return INVALID_OPERATION;
310 }
311
312 mState = STATE_RUNNING;
313
314 return OK;
315}
316
Wei Jia53692fa2017-12-11 10:33:46 -0800317status_t NuPlayer2Driver::pause() {
318 ALOGD("pause(%p)", this);
319 // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
320 // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
321 // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
322 // getCurrentPosition here.
Wei Jia800fe372018-02-20 15:00:45 -0800323 int64_t unused;
Wei Jia53692fa2017-12-11 10:33:46 -0800324 getCurrentPosition(&unused);
325
326 Mutex::Autolock autoLock(mLock);
327
328 switch (mState) {
329 case STATE_PAUSED:
330 case STATE_PREPARED:
331 return OK;
332
333 case STATE_RUNNING:
334 mState = STATE_PAUSED;
Wei Jia53692fa2017-12-11 10:33:46 -0800335 mPlayer->pause();
336 break;
337
338 default:
339 return INVALID_OPERATION;
340 }
341
342 return OK;
343}
344
345bool NuPlayer2Driver::isPlaying() {
346 return mState == STATE_RUNNING && !mAtEOS;
347}
348
349status_t NuPlayer2Driver::setPlaybackSettings(const AudioPlaybackRate &rate) {
350 status_t err = mPlayer->setPlaybackSettings(rate);
351 if (err == OK) {
352 // try to update position
Wei Jia800fe372018-02-20 15:00:45 -0800353 int64_t unused;
Wei Jia53692fa2017-12-11 10:33:46 -0800354 getCurrentPosition(&unused);
Wei Jia53692fa2017-12-11 10:33:46 -0800355 }
356 return err;
357}
358
359status_t NuPlayer2Driver::getPlaybackSettings(AudioPlaybackRate *rate) {
360 return mPlayer->getPlaybackSettings(rate);
361}
362
363status_t NuPlayer2Driver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
364 return mPlayer->setSyncSettings(sync, videoFpsHint);
365}
366
367status_t NuPlayer2Driver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
368 return mPlayer->getSyncSettings(sync, videoFps);
369}
370
Wei Jia800fe372018-02-20 15:00:45 -0800371status_t NuPlayer2Driver::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
372 ALOGD("seekTo(%p) (%lld ms, %d) at state %d", this, (long long)msec, mode, mState);
Wei Jia53692fa2017-12-11 10:33:46 -0800373 Mutex::Autolock autoLock(mLock);
374
375 int64_t seekTimeUs = msec * 1000ll;
376
377 switch (mState) {
378 case STATE_PREPARED:
Wei Jia53692fa2017-12-11 10:33:46 -0800379 case STATE_PAUSED:
380 case STATE_RUNNING:
381 {
382 mAtEOS = false;
383 mSeekInProgress = true;
Wei Jia53692fa2017-12-11 10:33:46 -0800384 mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
385 break;
386 }
387
388 default:
389 return INVALID_OPERATION;
390 }
391
392 mPositionUs = seekTimeUs;
393 return OK;
394}
395
Wei Jia800fe372018-02-20 15:00:45 -0800396status_t NuPlayer2Driver::getCurrentPosition(int64_t *msec) {
Wei Jia53692fa2017-12-11 10:33:46 -0800397 int64_t tempUs = 0;
398 {
399 Mutex::Autolock autoLock(mLock);
400 if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
401 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
Wei Jia800fe372018-02-20 15:00:45 -0800402 *msec = divRound(tempUs, (int64_t)(1000));
Wei Jia53692fa2017-12-11 10:33:46 -0800403 return OK;
404 }
405 }
406
407 status_t ret = mPlayer->getCurrentPosition(&tempUs);
408
409 Mutex::Autolock autoLock(mLock);
410 // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
411 // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
412 // position value that's different the seek to position.
413 if (ret != OK) {
414 tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
415 } else {
416 mPositionUs = tempUs;
417 }
Wei Jia800fe372018-02-20 15:00:45 -0800418 *msec = divRound(tempUs, (int64_t)(1000));
Wei Jia53692fa2017-12-11 10:33:46 -0800419 return OK;
420}
421
Wei Jia800fe372018-02-20 15:00:45 -0800422status_t NuPlayer2Driver::getDuration(int64_t *msec) {
Wei Jia53692fa2017-12-11 10:33:46 -0800423 Mutex::Autolock autoLock(mLock);
424
425 if (mDurationUs < 0) {
426 return UNKNOWN_ERROR;
427 }
428
429 *msec = (mDurationUs + 500ll) / 1000;
430
431 return OK;
432}
433
434void NuPlayer2Driver::updateMetrics(const char *where) {
435 if (where == NULL) {
436 where = "unknown";
437 }
438 ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
439
440 // gather the final stats for this record
441 Vector<sp<AMessage>> trackStats;
442 mPlayer->getStats(&trackStats);
443
444 if (trackStats.size() > 0) {
445 for (size_t i = 0; i < trackStats.size(); ++i) {
446 const sp<AMessage> &stats = trackStats.itemAt(i);
447
448 AString mime;
449 stats->findString("mime", &mime);
450
451 AString name;
452 stats->findString("component-name", &name);
453
454 if (mime.startsWith("video/")) {
455 int32_t width, height;
456 mAnalyticsItem->setCString(kPlayerVMime, mime.c_str());
457 if (!name.empty()) {
458 mAnalyticsItem->setCString(kPlayerVCodec, name.c_str());
459 }
460
461 if (stats->findInt32("width", &width)
462 && stats->findInt32("height", &height)) {
463 mAnalyticsItem->setInt32(kPlayerWidth, width);
464 mAnalyticsItem->setInt32(kPlayerHeight, height);
465 }
466
467 int64_t numFramesTotal = 0;
468 int64_t numFramesDropped = 0;
469 stats->findInt64("frames-total", &numFramesTotal);
470 stats->findInt64("frames-dropped-output", &numFramesDropped);
471
472 mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal);
473 mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
474
475
476 } else if (mime.startsWith("audio/")) {
477 mAnalyticsItem->setCString(kPlayerAMime, mime.c_str());
478 if (!name.empty()) {
479 mAnalyticsItem->setCString(kPlayerACodec, name.c_str());
480 }
481 }
482 }
483 }
484
485 // always provide duration and playing time, even if they have 0/unknown values.
486
487 // getDuration() uses mLock for mutex -- careful where we use it.
Wei Jia800fe372018-02-20 15:00:45 -0800488 int64_t duration_ms = -1;
Wei Jia53692fa2017-12-11 10:33:46 -0800489 getDuration(&duration_ms);
490 mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
491
492 mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
493
494 if (mRebufferingEvents != 0) {
495 mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
496 mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
497 mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
498 }
499
500 mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
501}
502
503
504void NuPlayer2Driver::logMetrics(const char *where) {
505 if (where == NULL) {
506 where = "unknown";
507 }
508 ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
509
510 if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
511 return;
512 }
513
514 // log only non-empty records
515 // we always updateMetrics() before we get here
516 // and that always injects 3 fields (duration, playing time, and
517 // datasource) into the record.
518 // So the canonical "empty" record has 3 elements in it.
519 if (mAnalyticsItem->count() > 3) {
520
Wei Jia53692fa2017-12-11 10:33:46 -0800521 mAnalyticsItem->selfrecord();
522
523 // re-init in case we prepare() and start() again.
524 delete mAnalyticsItem ;
Ray Essickee54eef2018-01-24 11:16:54 -0800525 mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
Wei Jia53692fa2017-12-11 10:33:46 -0800526 if (mAnalyticsItem) {
Wei Jia53692fa2017-12-11 10:33:46 -0800527 mAnalyticsItem->setUid(mClientUid);
528 }
529 } else {
530 ALOGV("did not have anything to record");
531 }
532}
533
534status_t NuPlayer2Driver::reset() {
535 ALOGD("reset(%p) at state %d", this, mState);
536
537 updateMetrics("reset");
538 logMetrics("reset");
539
540 Mutex::Autolock autoLock(mLock);
541
542 switch (mState) {
543 case STATE_IDLE:
544 return OK;
545
546 case STATE_SET_DATASOURCE_PENDING:
547 case STATE_RESET_IN_PROGRESS:
548 return INVALID_OPERATION;
549
550 case STATE_PREPARING:
551 {
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800552 notifyListener_l(mSrcId, MEDIA2_PREPARED);
Wei Jia53692fa2017-12-11 10:33:46 -0800553 break;
554 }
555
556 default:
557 break;
558 }
559
Wei Jia53692fa2017-12-11 10:33:46 -0800560 mState = STATE_RESET_IN_PROGRESS;
561 mPlayer->resetAsync();
562
563 while (mState == STATE_RESET_IN_PROGRESS) {
564 mCondition.wait(mLock);
565 }
566
567 mDurationUs = -1;
568 mPositionUs = -1;
569 mLooping = false;
570 mPlayingTimeUs = 0;
571 mRebufferingTimeUs = 0;
572 mRebufferingEvents = 0;
573 mRebufferingAtExit = false;
574
575 return OK;
576}
577
578status_t NuPlayer2Driver::notifyAt(int64_t mediaTimeUs) {
579 ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
580 return mPlayer->notifyAt(mediaTimeUs);
581}
582
583status_t NuPlayer2Driver::setLooping(int loop) {
584 mLooping = loop != 0;
585 return OK;
586}
587
Dongwon Kang9f631982018-07-10 12:34:41 -0700588status_t NuPlayer2Driver::invoke(const PlayerMessage &request, PlayerMessage *response) {
589 if (response == NULL) {
Wei Jia53692fa2017-12-11 10:33:46 -0800590 ALOGE("reply is a NULL pointer");
591 return BAD_VALUE;
592 }
593
Dongwon Kang9f631982018-07-10 12:34:41 -0700594 RepeatedPtrField<const Value>::const_iterator it = request.values().cbegin();
595 int32_t methodId = (it++)->int32_value();
Wei Jia53692fa2017-12-11 10:33:46 -0800596
597 switch (methodId) {
598 case MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE:
599 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700600 int mode = (it++)->int32_value();
Wei Jia53692fa2017-12-11 10:33:46 -0800601 return mPlayer->setVideoScalingMode(mode);
602 }
603
604 case MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO:
605 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700606 return mPlayer->getTrackInfo(response);
Wei Jia53692fa2017-12-11 10:33:46 -0800607 }
608
609 case MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK:
610 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700611 int trackIndex = (it++)->int32_value();
Wei Jia800fe372018-02-20 15:00:45 -0800612 int64_t msec = 0;
Wei Jia53692fa2017-12-11 10:33:46 -0800613 // getCurrentPosition should always return OK
614 getCurrentPosition(&msec);
615 return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll);
616 }
617
618 case MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK:
619 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700620 int trackIndex = (it++)->int32_value();
Wei Jia53692fa2017-12-11 10:33:46 -0800621 return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
622 }
623
624 case MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK:
625 {
Dongwon Kang9f631982018-07-10 12:34:41 -0700626 int32_t type = (it++)->int32_value();
627 return mPlayer->getSelectedTrack(type, response);
Wei Jia53692fa2017-12-11 10:33:46 -0800628 }
629
630 default:
631 {
632 return INVALID_OPERATION;
633 }
634 }
635}
636
637void NuPlayer2Driver::setAudioSink(const sp<AudioSink> &audioSink) {
638 mPlayer->setAudioSink(audioSink);
639 mAudioSink = audioSink;
640}
641
642status_t NuPlayer2Driver::setParameter(
643 int /* key */, const Parcel & /* request */) {
644 return INVALID_OPERATION;
645}
646
647status_t NuPlayer2Driver::getParameter(int key, Parcel *reply) {
648
649 if (key == FOURCC('m','t','r','X')) {
650 // mtrX -- a play on 'metrics' (not matrix)
651 // gather current info all together, parcel it, and send it back
652 updateMetrics("api");
653 mAnalyticsItem->writeToParcel(reply);
654 return OK;
655 }
656
657 return INVALID_OPERATION;
658}
659
660status_t NuPlayer2Driver::getMetadata(
661 const media::Metadata::Filter& /* ids */, Parcel *records) {
662 Mutex::Autolock autoLock(mLock);
663
664 using media::Metadata;
665
666 Metadata meta(records);
667
668 meta.appendBool(
669 Metadata::kPauseAvailable,
670 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_PAUSE);
671
672 meta.appendBool(
673 Metadata::kSeekBackwardAvailable,
674 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK_BACKWARD);
675
676 meta.appendBool(
677 Metadata::kSeekForwardAvailable,
678 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK_FORWARD);
679
680 meta.appendBool(
681 Metadata::kSeekAvailable,
682 mPlayerFlags & NuPlayer2::Source::FLAG_CAN_SEEK);
683
684 return OK;
685}
686
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800687void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
Wei Jia53692fa2017-12-11 10:33:46 -0800688 ALOGD("notifyResetComplete(%p)", this);
689 Mutex::Autolock autoLock(mLock);
690
691 CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
692 mState = STATE_IDLE;
693 mCondition.broadcast();
694}
695
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800696void NuPlayer2Driver::notifySetSurfaceComplete(int64_t /* srcId */) {
Wei Jia53692fa2017-12-11 10:33:46 -0800697 ALOGV("notifySetSurfaceComplete(%p)", this);
698 Mutex::Autolock autoLock(mLock);
699
700 CHECK(mSetSurfaceInProgress);
701 mSetSurfaceInProgress = false;
702
703 mCondition.broadcast();
704}
705
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800706void NuPlayer2Driver::notifyDuration(int64_t /* srcId */, int64_t durationUs) {
Wei Jia53692fa2017-12-11 10:33:46 -0800707 Mutex::Autolock autoLock(mLock);
708 mDurationUs = durationUs;
709}
710
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800711void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t /* srcId */, int64_t playingUs) {
Wei Jia53692fa2017-12-11 10:33:46 -0800712 Mutex::Autolock autoLock(mLock);
713 mPlayingTimeUs += playingUs;
714}
715
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800716void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t /* srcId */, int64_t rebufferingUs) {
Wei Jia53692fa2017-12-11 10:33:46 -0800717 Mutex::Autolock autoLock(mLock);
718 mRebufferingTimeUs += rebufferingUs;
719 mRebufferingEvents++;
720}
721
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800722void NuPlayer2Driver::notifyRebufferingWhenExit(int64_t /* srcId */, bool status) {
Wei Jia53692fa2017-12-11 10:33:46 -0800723 Mutex::Autolock autoLock(mLock);
724 mRebufferingAtExit = status;
725}
726
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800727void NuPlayer2Driver::notifySeekComplete(int64_t srcId) {
Wei Jia53692fa2017-12-11 10:33:46 -0800728 ALOGV("notifySeekComplete(%p)", this);
729 Mutex::Autolock autoLock(mLock);
730 mSeekInProgress = false;
Wei Jia0151ef42018-08-24 16:40:21 -0700731 notifyListener_l(srcId, MEDIA2_SEEK_COMPLETE);
Wei Jia53692fa2017-12-11 10:33:46 -0800732}
733
734status_t NuPlayer2Driver::dump(
735 int fd, const Vector<String16> & /* args */) const {
736
737 Vector<sp<AMessage> > trackStats;
738 mPlayer->getStats(&trackStats);
739
740 AString logString(" NuPlayer2\n");
741 char buf[256] = {0};
742
743 bool locked = false;
744 for (int i = 0; i < kDumpLockRetries; ++i) {
745 if (mLock.tryLock() == NO_ERROR) {
746 locked = true;
747 break;
748 }
749 usleep(kDumpLockSleepUs);
750 }
751
752 if (locked) {
753 snprintf(buf, sizeof(buf), " state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
754 mState, mAtEOS, mLooping, mAutoLoop);
755 mLock.unlock();
756 } else {
757 snprintf(buf, sizeof(buf), " NPD(%p) lock is taken\n", this);
758 }
759 logString.append(buf);
760
761 for (size_t i = 0; i < trackStats.size(); ++i) {
762 const sp<AMessage> &stats = trackStats.itemAt(i);
763
764 AString mime;
765 if (stats->findString("mime", &mime)) {
766 snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str());
767 logString.append(buf);
768 }
769
770 AString name;
771 if (stats->findString("component-name", &name)) {
772 snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str());
773 logString.append(buf);
774 }
775
776 if (mime.startsWith("video/")) {
777 int32_t width, height;
778 if (stats->findInt32("width", &width)
779 && stats->findInt32("height", &height)) {
780 snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height);
781 logString.append(buf);
782 }
783
784 int64_t numFramesTotal = 0;
785 int64_t numFramesDropped = 0;
786
787 stats->findInt64("frames-total", &numFramesTotal);
788 stats->findInt64("frames-dropped-output", &numFramesDropped);
789 snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), "
790 "percentageDropped(%.2f%%)\n",
791 (long long)numFramesTotal,
792 (long long)numFramesDropped,
793 numFramesTotal == 0
794 ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
795 logString.append(buf);
796 }
797 }
798
799 ALOGI("%s", logString.c_str());
800
801 if (fd >= 0) {
802 FILE *out = fdopen(dup(fd), "w");
803 fprintf(out, "%s", logString.c_str());
804 fclose(out);
805 out = NULL;
806 }
807
808 return OK;
809}
810
Wei Jia12b9f4a2017-12-13 15:24:13 -0800811void NuPlayer2Driver::onMessageReceived(const sp<AMessage> &msg) {
812 switch (msg->what()) {
813 case kWhatNotifyListener: {
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800814 int64_t srcId;
Wei Jia12b9f4a2017-12-13 15:24:13 -0800815 int32_t msgId;
Wei Jiac5c79da2017-12-21 18:03:05 -0800816 int32_t ext1 = 0;
817 int32_t ext2 = 0;
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800818 CHECK(msg->findInt64("srcId", &srcId));
Wei Jia12b9f4a2017-12-13 15:24:13 -0800819 CHECK(msg->findInt32("messageId", &msgId));
Wei Jiac5c79da2017-12-21 18:03:05 -0800820 msg->findInt32("ext1", &ext1);
821 msg->findInt32("ext2", &ext2);
Dongwon Kang41929fb2018-09-09 08:29:56 -0700822 sp<PlayerMessageWrapper> in;
Wei Jiac5c79da2017-12-21 18:03:05 -0800823 sp<RefBase> obj;
Dongwon Kang41929fb2018-09-09 08:29:56 -0700824 if (msg->findObject("obj", &obj) && obj != NULL) {
825 in = static_cast<PlayerMessageWrapper *>(obj.get());
Wei Jiac5c79da2017-12-21 18:03:05 -0800826 }
Dongwon Kang41929fb2018-09-09 08:29:56 -0700827 sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getPlayerMessage()));
Wei Jia12b9f4a2017-12-13 15:24:13 -0800828 break;
829 }
830 default:
831 break;
832 }
833}
834
Wei Jia53692fa2017-12-11 10:33:46 -0800835void NuPlayer2Driver::notifyListener(
Dongwon Kang41929fb2018-09-09 08:29:56 -0700836 int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
Wei Jia53692fa2017-12-11 10:33:46 -0800837 Mutex::Autolock autoLock(mLock);
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800838 notifyListener_l(srcId, msg, ext1, ext2, in);
Wei Jia53692fa2017-12-11 10:33:46 -0800839}
840
841void NuPlayer2Driver::notifyListener_l(
Dongwon Kang41929fb2018-09-09 08:29:56 -0700842 int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800843 ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
844 this, (long long)srcId, msg, ext1, ext2,
Dongwon Kang41929fb2018-09-09 08:29:56 -0700845 (in == NULL ? -1 : (int)in->ByteSize()), mAutoLoop, mLooping);
Wei Jia57aeffd2018-02-15 16:01:14 -0800846 if (srcId == mSrcId) {
847 switch (msg) {
848 case MEDIA2_PLAYBACK_COMPLETE:
849 {
850 if (mState != STATE_RESET_IN_PROGRESS) {
851 if (mAutoLoop) {
852 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
853 if (mAudioSink != NULL) {
854 streamType = mAudioSink->getAudioStreamType();
855 }
856 if (streamType == AUDIO_STREAM_NOTIFICATION) {
857 ALOGW("disabling auto-loop for notification");
858 mAutoLoop = false;
859 }
Wei Jia53692fa2017-12-11 10:33:46 -0800860 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800861 if (mLooping || mAutoLoop) {
862 mPlayer->seekToAsync(0);
863 if (mAudioSink != NULL) {
864 // The renderer has stopped the sink at the end in order to play out
865 // the last little bit of audio. In looping mode, we need to restart it.
866 mAudioSink->start();
867 }
Wei Jia9af566a2018-08-10 16:36:35 -0700868
869 sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
870 notify->setInt64("srcId", srcId);
871 notify->setInt32("messageId", MEDIA2_INFO);
872 notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
873 notify->post();
Wei Jia57aeffd2018-02-15 16:01:14 -0800874 return;
Wei Jia53692fa2017-12-11 10:33:46 -0800875 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800876 if (property_get_bool("persist.debug.sf.stats", false)) {
877 Vector<String16> args;
878 dump(-1, args);
Wei Jia53692fa2017-12-11 10:33:46 -0800879 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800880 mPlayer->pause();
881 mState = STATE_PAUSED;
Wei Jia53692fa2017-12-11 10:33:46 -0800882 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800883 // fall through
Wei Jia53692fa2017-12-11 10:33:46 -0800884 }
Wei Jia53692fa2017-12-11 10:33:46 -0800885
Wei Jia57aeffd2018-02-15 16:01:14 -0800886 case MEDIA2_ERROR:
887 {
888 // when we have an error, add it to the analytics for this playback.
889 // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
890 // [test against msg is due to fall through from previous switch value]
891 if (msg == MEDIA2_ERROR) {
892 mAnalyticsItem->setInt32(kPlayerError, ext1);
893 if (ext2 != 0) {
894 mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
895 }
896 mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
Wei Jia53692fa2017-12-11 10:33:46 -0800897 }
Wei Jia57aeffd2018-02-15 16:01:14 -0800898 mAtEOS = true;
899 break;
Wei Jia53692fa2017-12-11 10:33:46 -0800900 }
Wei Jia53692fa2017-12-11 10:33:46 -0800901
Wei Jia57aeffd2018-02-15 16:01:14 -0800902 default:
903 break;
904 }
Wei Jia53692fa2017-12-11 10:33:46 -0800905 }
906
Wei Jiac5c79da2017-12-21 18:03:05 -0800907 sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800908 notify->setInt64("srcId", srcId);
Wei Jiac5c79da2017-12-21 18:03:05 -0800909 notify->setInt32("messageId", msg);
910 notify->setInt32("ext1", ext1);
911 notify->setInt32("ext2", ext2);
Dongwon Kang41929fb2018-09-09 08:29:56 -0700912 notify->setObject("obj", PlayerMessageWrapper::Create((PlayerMessage*)in));
Wei Jiac5c79da2017-12-21 18:03:05 -0800913 notify->post();
Wei Jia12b9f4a2017-12-13 15:24:13 -0800914}
915
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800916void NuPlayer2Driver::notifySetDataSourceCompleted(int64_t /* srcId */, status_t err) {
Wei Jia53692fa2017-12-11 10:33:46 -0800917 Mutex::Autolock autoLock(mLock);
918
919 CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
920
921 mAsyncResult = err;
922 mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
923 mCondition.broadcast();
924}
925
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800926void NuPlayer2Driver::notifyPrepareCompleted(int64_t srcId, status_t err) {
Wei Jia53692fa2017-12-11 10:33:46 -0800927 ALOGV("notifyPrepareCompleted %d", err);
928
929 Mutex::Autolock autoLock(mLock);
930
Wei Jia57aeffd2018-02-15 16:01:14 -0800931 if (srcId != mSrcId) {
932 if (err == OK) {
933 notifyListener_l(srcId, MEDIA2_PREPARED);
934 } else {
935 notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
936 }
937 return;
938 }
939
Wei Jia53692fa2017-12-11 10:33:46 -0800940 if (mState != STATE_PREPARING) {
941 // We were preparing asynchronously when the client called
942 // reset(), we sent a premature "prepared" notification and
943 // then initiated the reset. This notification is stale.
944 CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
945 return;
946 }
947
948 CHECK_EQ(mState, STATE_PREPARING);
949
950 mAsyncResult = err;
951
952 if (err == OK) {
953 // update state before notifying client, so that if client calls back into NuPlayer2Driver
954 // in response, NuPlayer2Driver has the right state
955 mState = STATE_PREPARED;
Wei Jia57aeffd2018-02-15 16:01:14 -0800956 notifyListener_l(srcId, MEDIA2_PREPARED);
Wei Jia53692fa2017-12-11 10:33:46 -0800957 } else {
958 mState = STATE_UNPREPARED;
Wei Jia57aeffd2018-02-15 16:01:14 -0800959 notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
Wei Jia53692fa2017-12-11 10:33:46 -0800960 }
961
962 sp<MetaData> meta = mPlayer->getFileMeta();
963 int32_t loop;
964 if (meta != NULL
965 && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
966 mAutoLoop = true;
967 }
968
969 mCondition.broadcast();
970}
971
Wei Jiad2bb1bd2018-02-08 09:47:37 -0800972void NuPlayer2Driver::notifyFlagsChanged(int64_t /* srcId */, uint32_t flags) {
Wei Jia53692fa2017-12-11 10:33:46 -0800973 Mutex::Autolock autoLock(mLock);
974
975 mPlayerFlags = flags;
976}
977
978// Modular DRM
979status_t NuPlayer2Driver::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
980{
981 ALOGV("prepareDrm(%p) state: %d", this, mState);
982
983 // leaving the state verification for mediaplayer.cpp
984 status_t ret = mPlayer->prepareDrm(uuid, drmSessionId);
985
986 ALOGV("prepareDrm ret: %d", ret);
987
988 return ret;
989}
990
991status_t NuPlayer2Driver::releaseDrm()
992{
993 ALOGV("releaseDrm(%p) state: %d", this, mState);
994
995 // leaving the state verification for mediaplayer.cpp
996 status_t ret = mPlayer->releaseDrm();
997
998 ALOGV("releaseDrm ret: %d", ret);
999
1000 return ret;
1001}
1002
Ray Essick51f4c872017-12-15 12:27:56 -08001003std::string NuPlayer2Driver::stateString(State state) {
1004 const char *rval = NULL;
1005 char rawbuffer[16]; // allows "%d"
1006
1007 switch (state) {
1008 case STATE_IDLE: rval = "IDLE"; break;
1009 case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
1010 case STATE_UNPREPARED: rval = "UNPREPARED"; break;
1011 case STATE_PREPARING: rval = "PREPARING"; break;
1012 case STATE_PREPARED: rval = "PREPARED"; break;
1013 case STATE_RUNNING: rval = "RUNNING"; break;
1014 case STATE_PAUSED: rval = "PAUSED"; break;
1015 case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
Ray Essick51f4c872017-12-15 12:27:56 -08001016 default:
1017 // yes, this buffer is shared and vulnerable to races
1018 snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
1019 rval = rawbuffer;
1020 break;
1021 }
1022
1023 return rval;
1024}
1025
Wei Jia53692fa2017-12-11 10:33:46 -08001026} // namespace android