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