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