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