NuPlayerDriver.cpp revision 377b2ec9a2885f9b6405b07ba900a9e3f4349c38
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(int key, const Parcel &request) {
425    return INVALID_OPERATION;
426}
427
428status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
429    return INVALID_OPERATION;
430}
431
432status_t NuPlayerDriver::getMetadata(
433        const media::Metadata::Filter& ids, Parcel *records) {
434    Mutex::Autolock autoLock(mLock);
435
436    using media::Metadata;
437
438    Metadata meta(records);
439
440    meta.appendBool(
441            Metadata::kPauseAvailable,
442            mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
443
444    meta.appendBool(
445            Metadata::kSeekBackwardAvailable,
446            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
447
448    meta.appendBool(
449            Metadata::kSeekForwardAvailable,
450            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
451
452    meta.appendBool(
453            Metadata::kSeekAvailable,
454            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
455
456    return OK;
457}
458
459void NuPlayerDriver::notifyResetComplete() {
460    Mutex::Autolock autoLock(mLock);
461
462    CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
463    mState = STATE_IDLE;
464    mCondition.broadcast();
465}
466
467void NuPlayerDriver::notifySetSurfaceComplete() {
468    Mutex::Autolock autoLock(mLock);
469
470    CHECK(mSetSurfaceInProgress);
471    mSetSurfaceInProgress = false;
472
473    mCondition.broadcast();
474}
475
476void NuPlayerDriver::notifyDuration(int64_t durationUs) {
477    Mutex::Autolock autoLock(mLock);
478    mDurationUs = durationUs;
479}
480
481void NuPlayerDriver::notifyPosition(int64_t positionUs) {
482    Mutex::Autolock autoLock(mLock);
483    mPositionUs = positionUs;
484}
485
486void NuPlayerDriver::notifySeekComplete() {
487    notifyListener(MEDIA_SEEK_COMPLETE);
488}
489
490void NuPlayerDriver::notifyFrameStats(
491        int64_t numFramesTotal, int64_t numFramesDropped) {
492    Mutex::Autolock autoLock(mLock);
493    mNumFramesTotal = numFramesTotal;
494    mNumFramesDropped = numFramesDropped;
495}
496
497status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const {
498    Mutex::Autolock autoLock(mLock);
499
500    FILE *out = fdopen(dup(fd), "w");
501
502    fprintf(out, " NuPlayer\n");
503    fprintf(out, "  numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), "
504                 "percentageDropped(%.2f)\n",
505                 mNumFramesTotal,
506                 mNumFramesDropped,
507                 mNumFramesTotal == 0
508                    ? 0.0 : (double)mNumFramesDropped / mNumFramesTotal);
509
510    fclose(out);
511    out = NULL;
512
513    return OK;
514}
515
516void NuPlayerDriver::notifyListener(
517        int msg, int ext1, int ext2, const Parcel *in) {
518    if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) {
519        mAtEOS = true;
520    }
521
522    sendEvent(msg, ext1, ext2, in);
523}
524
525void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
526    Mutex::Autolock autoLock(mLock);
527
528    CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
529
530    mAsyncResult = err;
531    mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
532    mCondition.broadcast();
533}
534
535void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
536    Mutex::Autolock autoLock(mLock);
537
538    if (mState != STATE_PREPARING) {
539        // We were preparing asynchronously when the client called
540        // reset(), we sent a premature "prepared" notification and
541        // then initiated the reset. This notification is stale.
542        CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
543        return;
544    }
545
546    CHECK_EQ(mState, STATE_PREPARING);
547
548    mAsyncResult = err;
549
550    if (err == OK) {
551        if (mIsAsyncPrepare) {
552            notifyListener(MEDIA_PREPARED);
553        }
554        mState = STATE_PREPARED;
555    } else {
556        if (mIsAsyncPrepare) {
557            notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
558        }
559        mState = STATE_UNPREPARED;
560    }
561
562    mCondition.broadcast();
563}
564
565void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
566    Mutex::Autolock autoLock(mLock);
567
568    mPlayerFlags = flags;
569}
570
571}  // namespace android
572