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