• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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