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