NuPlayerDriver.cpp revision d411b4ca2945cd8974a3a78199fce94646950128
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
22#include "NuPlayerDriver.h"
23
24#include "NuPlayer.h"
25#include "NuPlayerSource.h"
26
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/ALooper.h>
29#include <media/stagefright/MetaData.h>
30
31namespace android {
32
33NuPlayerDriver::NuPlayerDriver()
34    : mState(STATE_IDLE),
35      mIsAsyncPrepare(false),
36      mAsyncResult(UNKNOWN_ERROR),
37      mSetSurfaceInProgress(false),
38      mDurationUs(-1),
39      mPositionUs(-1),
40      mNumFramesTotal(0),
41      mNumFramesDropped(0),
42      mLooper(new ALooper),
43      mPlayerFlags(0),
44      mAtEOS(false),
45      mStartupSeekTimeUs(-1) {
46    mLooper->setName("NuPlayerDriver Looper");
47
48    mLooper->start(
49            false, /* runOnCallingThread */
50            true,  /* canCallJava */
51            PRIORITY_AUDIO);
52
53    mPlayer = new NuPlayer;
54    mLooper->registerHandler(mPlayer);
55
56    mPlayer->setDriver(this);
57}
58
59NuPlayerDriver::~NuPlayerDriver() {
60    mLooper->stop();
61}
62
63status_t NuPlayerDriver::initCheck() {
64    return OK;
65}
66
67status_t NuPlayerDriver::setUID(uid_t uid) {
68    mPlayer->setUID(uid);
69
70    return OK;
71}
72
73status_t NuPlayerDriver::setDataSource(
74        const char *url, const KeyedVector<String8, String8> *headers) {
75    Mutex::Autolock autoLock(mLock);
76
77    if (mState != STATE_IDLE) {
78        return INVALID_OPERATION;
79    }
80
81    mState = STATE_SET_DATASOURCE_PENDING;
82
83    mPlayer->setDataSourceAsync(url, headers);
84
85    while (mState == STATE_SET_DATASOURCE_PENDING) {
86        mCondition.wait(mLock);
87    }
88
89    return mAsyncResult;
90}
91
92status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
93    Mutex::Autolock autoLock(mLock);
94
95    if (mState != STATE_IDLE) {
96        return INVALID_OPERATION;
97    }
98
99    mState = STATE_SET_DATASOURCE_PENDING;
100
101    mPlayer->setDataSourceAsync(fd, offset, length);
102
103    while (mState == STATE_SET_DATASOURCE_PENDING) {
104        mCondition.wait(mLock);
105    }
106
107    return mAsyncResult;
108}
109
110status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
111    Mutex::Autolock autoLock(mLock);
112
113    if (mState != STATE_IDLE) {
114        return INVALID_OPERATION;
115    }
116
117    mState = STATE_SET_DATASOURCE_PENDING;
118
119    mPlayer->setDataSourceAsync(source);
120
121    while (mState == STATE_SET_DATASOURCE_PENDING) {
122        mCondition.wait(mLock);
123    }
124
125    return mAsyncResult;
126}
127
128status_t NuPlayerDriver::setVideoSurfaceTexture(
129        const sp<IGraphicBufferProducer> &bufferProducer) {
130    Mutex::Autolock autoLock(mLock);
131
132    if (mSetSurfaceInProgress) {
133        return INVALID_OPERATION;
134    }
135
136    switch (mState) {
137        case STATE_SET_DATASOURCE_PENDING:
138        case STATE_RESET_IN_PROGRESS:
139            return INVALID_OPERATION;
140
141        default:
142            break;
143    }
144
145    mSetSurfaceInProgress = true;
146
147    mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
148
149    while (mSetSurfaceInProgress) {
150        mCondition.wait(mLock);
151    }
152
153    return OK;
154}
155
156status_t NuPlayerDriver::prepare() {
157    Mutex::Autolock autoLock(mLock);
158    return prepare_l();
159}
160
161status_t NuPlayerDriver::prepare_l() {
162    switch (mState) {
163        case STATE_UNPREPARED:
164            mState = STATE_PREPARING;
165
166            // Make sure we're not posting any notifications, success or
167            // failure information is only communicated through our result
168            // code.
169            mIsAsyncPrepare = false;
170            mPlayer->prepareAsync();
171            while (mState == STATE_PREPARING) {
172                mCondition.wait(mLock);
173            }
174            return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
175        default:
176            return INVALID_OPERATION;
177    };
178}
179
180status_t NuPlayerDriver::prepareAsync() {
181    Mutex::Autolock autoLock(mLock);
182
183    switch (mState) {
184        case STATE_UNPREPARED:
185            mState = STATE_PREPARING;
186            mIsAsyncPrepare = true;
187            mPlayer->prepareAsync();
188            return OK;
189        default:
190            return INVALID_OPERATION;
191    };
192}
193
194status_t NuPlayerDriver::start() {
195    Mutex::Autolock autoLock(mLock);
196
197    switch (mState) {
198        case STATE_UNPREPARED:
199        {
200            status_t err = prepare_l();
201
202            if (err != OK) {
203                return err;
204            }
205
206            CHECK_EQ(mState, STATE_PREPARED);
207
208            // fall through
209        }
210
211        case STATE_PREPARED:
212        {
213            mAtEOS = false;
214            mPlayer->start();
215
216            if (mStartupSeekTimeUs >= 0) {
217                if (mStartupSeekTimeUs == 0) {
218                    notifySeekComplete();
219                } else {
220                    mPlayer->seekToAsync(mStartupSeekTimeUs);
221                }
222
223                mStartupSeekTimeUs = -1;
224            }
225            break;
226        }
227
228        case STATE_RUNNING:
229            break;
230
231        case STATE_PAUSED:
232        {
233            mPlayer->resume();
234            break;
235        }
236
237        default:
238            return INVALID_OPERATION;
239    }
240
241    mState = STATE_RUNNING;
242
243    return OK;
244}
245
246status_t NuPlayerDriver::stop() {
247    return pause();
248}
249
250status_t NuPlayerDriver::pause() {
251    Mutex::Autolock autoLock(mLock);
252
253    switch (mState) {
254        case STATE_PAUSED:
255        case STATE_PREPARED:
256            return OK;
257
258        case STATE_RUNNING:
259            notifyListener(MEDIA_PAUSED);
260            mPlayer->pause();
261            break;
262
263        default:
264            return INVALID_OPERATION;
265    }
266
267    mState = STATE_PAUSED;
268
269    return OK;
270}
271
272bool NuPlayerDriver::isPlaying() {
273    return mState == STATE_RUNNING && !mAtEOS;
274}
275
276status_t NuPlayerDriver::seekTo(int msec) {
277    Mutex::Autolock autoLock(mLock);
278
279    int64_t seekTimeUs = msec * 1000ll;
280
281    switch (mState) {
282        case STATE_PREPARED:
283        {
284            mStartupSeekTimeUs = seekTimeUs;
285            break;
286        }
287
288        case STATE_RUNNING:
289        case STATE_PAUSED:
290        {
291            mAtEOS = false;
292            // seeks can take a while, so we essentially paused
293            notifyListener(MEDIA_PAUSED);
294            mPlayer->seekToAsync(seekTimeUs);
295            break;
296        }
297
298        default:
299            return INVALID_OPERATION;
300    }
301
302    return OK;
303}
304
305status_t NuPlayerDriver::getCurrentPosition(int *msec) {
306    Mutex::Autolock autoLock(mLock);
307
308    if (mPositionUs < 0) {
309        *msec = 0;
310    } else {
311        *msec = (mPositionUs + 500ll) / 1000;
312    }
313
314    return OK;
315}
316
317status_t NuPlayerDriver::getDuration(int *msec) {
318    Mutex::Autolock autoLock(mLock);
319
320    if (mDurationUs < 0) {
321        return UNKNOWN_ERROR;
322    }
323
324    *msec = (mDurationUs + 500ll) / 1000;
325
326    return OK;
327}
328
329status_t NuPlayerDriver::reset() {
330    Mutex::Autolock autoLock(mLock);
331
332    switch (mState) {
333        case STATE_IDLE:
334            return OK;
335
336        case STATE_SET_DATASOURCE_PENDING:
337        case STATE_RESET_IN_PROGRESS:
338            return INVALID_OPERATION;
339
340        case STATE_PREPARING:
341        {
342            CHECK(mIsAsyncPrepare);
343
344            notifyListener(MEDIA_PREPARED);
345            break;
346        }
347
348        default:
349            break;
350    }
351
352    notifyListener(MEDIA_STOPPED);
353
354    mState = STATE_RESET_IN_PROGRESS;
355    mPlayer->resetAsync();
356
357    while (mState == STATE_RESET_IN_PROGRESS) {
358        mCondition.wait(mLock);
359    }
360
361    mDurationUs = -1;
362    mPositionUs = -1;
363    mStartupSeekTimeUs = -1;
364
365    return OK;
366}
367
368status_t NuPlayerDriver::setLooping(int /* loop */) {
369    return INVALID_OPERATION;
370}
371
372player_type NuPlayerDriver::playerType() {
373    return NU_PLAYER;
374}
375
376status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
377    if (reply == NULL) {
378        ALOGE("reply is a NULL pointer");
379        return BAD_VALUE;
380    }
381
382    int32_t methodId;
383    status_t ret = request.readInt32(&methodId);
384    if (ret != OK) {
385        ALOGE("Failed to retrieve the requested method to invoke");
386        return ret;
387    }
388
389    switch (methodId) {
390        case INVOKE_ID_SET_VIDEO_SCALING_MODE:
391        {
392            int mode = request.readInt32();
393            return mPlayer->setVideoScalingMode(mode);
394        }
395
396        case INVOKE_ID_GET_TRACK_INFO:
397        {
398            return mPlayer->getTrackInfo(reply);
399        }
400
401        case INVOKE_ID_SELECT_TRACK:
402        {
403            int trackIndex = request.readInt32();
404            return mPlayer->selectTrack(trackIndex, true /* select */);
405        }
406
407        case INVOKE_ID_UNSELECT_TRACK:
408        {
409            int trackIndex = request.readInt32();
410            return mPlayer->selectTrack(trackIndex, false /* select */);
411        }
412
413        default:
414        {
415            return INVALID_OPERATION;
416        }
417    }
418}
419
420void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
421    mPlayer->setAudioSink(audioSink);
422}
423
424status_t NuPlayerDriver::setParameter(
425        int /* key */, const Parcel & /* request */) {
426    return INVALID_OPERATION;
427}
428
429status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
430    return INVALID_OPERATION;
431}
432
433status_t NuPlayerDriver::getMetadata(
434        const media::Metadata::Filter& /* ids */, Parcel *records) {
435    Mutex::Autolock autoLock(mLock);
436
437    using media::Metadata;
438
439    Metadata meta(records);
440
441    meta.appendBool(
442            Metadata::kPauseAvailable,
443            mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
444
445    meta.appendBool(
446            Metadata::kSeekBackwardAvailable,
447            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
448
449    meta.appendBool(
450            Metadata::kSeekForwardAvailable,
451            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
452
453    meta.appendBool(
454            Metadata::kSeekAvailable,
455            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
456
457    return OK;
458}
459
460void NuPlayerDriver::notifyResetComplete() {
461    Mutex::Autolock autoLock(mLock);
462
463    CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
464    mState = STATE_IDLE;
465    mCondition.broadcast();
466}
467
468void NuPlayerDriver::notifySetSurfaceComplete() {
469    Mutex::Autolock autoLock(mLock);
470
471    CHECK(mSetSurfaceInProgress);
472    mSetSurfaceInProgress = false;
473
474    mCondition.broadcast();
475}
476
477void NuPlayerDriver::notifyDuration(int64_t durationUs) {
478    Mutex::Autolock autoLock(mLock);
479    mDurationUs = durationUs;
480}
481
482void NuPlayerDriver::notifyPosition(int64_t positionUs) {
483    Mutex::Autolock autoLock(mLock);
484    mPositionUs = positionUs;
485}
486
487void NuPlayerDriver::notifySeekComplete() {
488    notifyListener(MEDIA_SEEK_COMPLETE);
489}
490
491void NuPlayerDriver::notifyFrameStats(
492        int64_t numFramesTotal, int64_t numFramesDropped) {
493    Mutex::Autolock autoLock(mLock);
494    mNumFramesTotal = numFramesTotal;
495    mNumFramesDropped = numFramesDropped;
496}
497
498status_t NuPlayerDriver::dump(
499        int fd, const Vector<String16> & /* args */) const {
500    Mutex::Autolock autoLock(mLock);
501
502    FILE *out = fdopen(dup(fd), "w");
503
504    fprintf(out, " NuPlayer\n");
505    fprintf(out, "  numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), "
506                 "percentageDropped(%.2f)\n",
507                 mNumFramesTotal,
508                 mNumFramesDropped,
509                 mNumFramesTotal == 0
510                    ? 0.0 : (double)mNumFramesDropped / mNumFramesTotal);
511
512    fclose(out);
513    out = NULL;
514
515    return OK;
516}
517
518void NuPlayerDriver::notifyListener(
519        int msg, int ext1, int ext2, const Parcel *in) {
520    if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) {
521        mAtEOS = true;
522    }
523
524    sendEvent(msg, ext1, ext2, in);
525}
526
527void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
528    Mutex::Autolock autoLock(mLock);
529
530    CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
531
532    mAsyncResult = err;
533    mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
534    mCondition.broadcast();
535}
536
537void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
538    Mutex::Autolock autoLock(mLock);
539
540    if (mState != STATE_PREPARING) {
541        // We were preparing asynchronously when the client called
542        // reset(), we sent a premature "prepared" notification and
543        // then initiated the reset. This notification is stale.
544        CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
545        return;
546    }
547
548    CHECK_EQ(mState, STATE_PREPARING);
549
550    mAsyncResult = err;
551
552    if (err == OK) {
553        if (mIsAsyncPrepare) {
554            notifyListener(MEDIA_PREPARED);
555        }
556        mState = STATE_PREPARED;
557    } else {
558        if (mIsAsyncPrepare) {
559            notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
560        }
561        mState = STATE_UNPREPARED;
562    }
563
564    mCondition.broadcast();
565}
566
567void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
568    Mutex::Autolock autoLock(mLock);
569
570    mPlayerFlags = flags;
571}
572
573}  // namespace android
574