NuPlayerDriver.cpp revision 21a1d72bb42710d149532653490154f89330b9dd
157b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien/*
257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * Copyright (C) 2010 The Android Open Source Project
357b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien *
457b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * Licensed under the Apache License, Version 2.0 (the "License");
557b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * you may not use this file except in compliance with the License.
657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * You may obtain a copy of the License at
757b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien *
857b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien *      http://www.apache.org/licenses/LICENSE-2.0
957b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien *
1057b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * Unless required by applicable law or agreed to in writing, software
1157b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * distributed under the License is distributed on an "AS IS" BASIS,
1257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1357b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * See the License for the specific language governing permissions and
1457b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien * limitations under the License.
1557b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien */
1657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
1757b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien//#define LOG_NDEBUG 0
1857b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#define LOG_TAG "NuPlayerDriver"
1957b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include <inttypes.h>
2057b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include <utils/Log.h>
2157b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
2257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include "NuPlayerDriver.h"
2357b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
2457b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include "NuPlayer.h"
2557b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include "NuPlayerSource.h"
2657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
2757b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include <media/stagefright/foundation/ADebug.h>
2857b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include <media/stagefright/foundation/ALooper.h>
2957b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include <media/stagefright/MetaData.h>
3057b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
3157b6dae9894b9362ef04517ff477fd491f9d433bRaph Leviennamespace android {
3257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
3357b6dae9894b9362ef04517ff477fd491f9d433bRaph LevienNuPlayerDriver::NuPlayerDriver()
3457b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    : mState(STATE_IDLE),
3557b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mIsAsyncPrepare(false),
3657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mAsyncResult(UNKNOWN_ERROR),
3757b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mSetSurfaceInProgress(false),
3857b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mDurationUs(-1),
3957b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mPositionUs(-1),
4057b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mNotifyTimeRealUs(-1),
4157b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mPauseStartedTimeUs(-1),
4257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mNumFramesTotal(0),
4357b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mNumFramesDropped(0),
4457b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mLooper(new ALooper),
45c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien      mPlayerFlags(0),
4657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mAtEOS(false),
4757b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mLooping(false),
4857b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mAutoLoop(false),
4957b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien      mStartupSeekTimeUs(-1) {
50c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    mLooper->setName("NuPlayerDriver Looper");
5157b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
5257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    mLooper->start(
5357b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien            false, /* runOnCallingThread */
5457b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien            true,  /* canCallJava */
5557b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien            PRIORITY_AUDIO);
5657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
5757b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    mPlayer = new NuPlayer;
5857b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    mLooper->registerHandler(mPlayer);
5957b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
6057b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    mPlayer->setDriver(this);
6157b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien}
6257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
63c88ef135fcc2661ec7addc171ebc60787df38affRaph LevienNuPlayerDriver::~NuPlayerDriver() {
6457b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    mLooper->stop();
6557b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien}
6657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
67c88ef135fcc2661ec7addc171ebc60787df38affRaph Levienstatus_t NuPlayerDriver::initCheck() {
6857b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    return OK;
6957b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien}
7057b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
7157b6dae9894b9362ef04517ff477fd491f9d433bRaph Levienstatus_t NuPlayerDriver::setUID(uid_t uid) {
7257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    mPlayer->setUID(uid);
7357b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
7457b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    return OK;
7557b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien}
7657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
7757b6dae9894b9362ef04517ff477fd491f9d433bRaph Levienstatus_t NuPlayerDriver::setDataSource(
7857b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien        const sp<IMediaHTTPService> &httpService,
7957b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien        const char *url,
80c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        const KeyedVector<String8, String8> *headers) {
8157b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    Mutex::Autolock autoLock(mLock);
8257b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien
8357b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien    ALOGV("setDataSource: url=%s", url);
84c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    if (mState != STATE_IDLE) {
8557b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien        return INVALID_OPERATION;
869c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    }
879c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
889c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    mState = STATE_SET_DATASOURCE_PENDING;
899c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
909c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    mPlayer->setDataSourceAsync(httpService, url, headers);
919c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
929c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    while (mState == STATE_SET_DATASOURCE_PENDING) {
939c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien        mCondition.wait(mLock);
946d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    }
956d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
96c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    return mAsyncResult;
976d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien}
989c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
99c88ef135fcc2661ec7addc171ebc60787df38affRaph Levienstatus_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
1009c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    Mutex::Autolock autoLock(mLock);
1019c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1029c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    ALOGV("setDataSource: fd=%d", fd);
103c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    if (mState != STATE_IDLE) {
1049c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien        return INVALID_OPERATION;
1059c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    }
1069c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1079c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    mState = STATE_SET_DATASOURCE_PENDING;
1089c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1099c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    mPlayer->setDataSourceAsync(fd, offset, length);
1109c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1119c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    while (mState == STATE_SET_DATASOURCE_PENDING) {
1129c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien        mCondition.wait(mLock);
1136d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    }
1146d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
115c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    return mAsyncResult;
1166d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien}
1176d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
118c88ef135fcc2661ec7addc171ebc60787df38affRaph Levienstatus_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
1196d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    Mutex::Autolock autoLock(mLock);
1209c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
121c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    ALOGV("setDataSource: stream source");
1229c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    if (mState != STATE_IDLE) {
1239c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien        return INVALID_OPERATION;
1249c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    }
125c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien
1269c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    mState = STATE_SET_DATASOURCE_PENDING;
1279c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1286d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    mPlayer->setDataSourceAsync(source);
1296d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
1309c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    while (mState == STATE_SET_DATASOURCE_PENDING) {
1319c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien        mCondition.wait(mLock);
1329c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    }
1339c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1349c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    return mAsyncResult;
1359c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien}
1369c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1376d15657e4a3826d4d47d5358f1dde211484527e9Raph Levienstatus_t NuPlayerDriver::setVideoSurfaceTexture(
1386d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        const sp<IGraphicBufferProducer> &bufferProducer) {
139c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    Mutex::Autolock autoLock(mLock);
1406d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
1419c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    if (mSetSurfaceInProgress) {
142c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        return INVALID_OPERATION;
1439c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    }
1449c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1459c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    switch (mState) {
146c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        case STATE_SET_DATASOURCE_PENDING:
1479c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien        case STATE_RESET_IN_PROGRESS:
1489c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            return INVALID_OPERATION;
1499c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1509c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien        default:
1519c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            break;
1529c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    }
1539c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1549c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    mSetSurfaceInProgress = true;
1559c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
1566d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
1576d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
158c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    while (mSetSurfaceInProgress) {
1596d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        mCondition.wait(mLock);
1609c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    }
161c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien
1629c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    return OK;
1639c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien}
1649c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien
165c88ef135fcc2661ec7addc171ebc60787df38affRaph Levienstatus_t NuPlayerDriver::prepare() {
1669c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    Mutex::Autolock autoLock(mLock);
1679c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien    return prepare_l();
1686d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien}
1696d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
1706d15657e4a3826d4d47d5358f1dde211484527e9Raph Levienstatus_t NuPlayerDriver::prepare_l() {
1716d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    switch (mState) {
1726d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_UNPREPARED:
1736d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mState = STATE_PREPARING;
1746d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
1756d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            // Make sure we're not posting any notifications, success or
1766d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            // failure information is only communicated through our result
177c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            // code.
1786d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mIsAsyncPrepare = false;
1796d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mPlayer->prepareAsync();
180c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            while (mState == STATE_PREPARING) {
1816d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                mCondition.wait(mLock);
1826d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            }
1836d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
184c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        case STATE_STOPPED:
1856d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            // this is really just paused. handle as seek to start
1866d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mAtEOS = false;
1879c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            mState = STATE_STOPPED_AND_PREPARING;
1889c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            mIsAsyncPrepare = false;
1899c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            mPlayer->seekToAsync(0);
1909c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            while (mState == STATE_STOPPED_AND_PREPARING) {
1919c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien                mCondition.wait(mLock);
1929c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            }
1939c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
1946d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        default:
1956d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            return INVALID_OPERATION;
196c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    };
1976d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien}
1986d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
199c88ef135fcc2661ec7addc171ebc60787df38affRaph Levienstatus_t NuPlayerDriver::prepareAsync() {
2006d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    Mutex::Autolock autoLock(mLock);
2016d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
202c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien    switch (mState) {
2036d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_UNPREPARED:
2049c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            mState = STATE_PREPARING;
205c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            mIsAsyncPrepare = true;
2069c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            mPlayer->prepareAsync();
2079c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            return OK;
2089c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien        case STATE_STOPPED:
209c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            // this is really just paused. handle as seek to start
2109c4cc648abcae144f3b99d612e58ef01d5e52cceRaph Levien            mAtEOS = false;
2116d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mState = STATE_STOPPED_AND_PREPARING;
2126d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mIsAsyncPrepare = true;
2136d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mPlayer->seekToAsync(0);
2146d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            return OK;
2156d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        default:
2166d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            return INVALID_OPERATION;
2176d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    };
2186d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien}
2196d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2206d15657e4a3826d4d47d5358f1dde211484527e9Raph Levienstatus_t NuPlayerDriver::start() {
2216d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    Mutex::Autolock autoLock(mLock);
222c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien
2236d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    switch (mState) {
2246d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_UNPREPARED:
225c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        {
2266d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            status_t err = prepare_l();
2276d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
228c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            if (err != OK) {
2296d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                return err;
2306d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            }
231c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien
2326d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            CHECK_EQ(mState, STATE_PREPARED);
2336d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
234c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            // fall through
2356d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        }
2366d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
237c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        case STATE_PREPARED:
2386d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        {
2396d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mAtEOS = false;
240c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            mPlayer->start();
2416d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2426d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            if (mStartupSeekTimeUs >= 0) {
243c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien                if (mStartupSeekTimeUs == 0) {
2446d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                    notifySeekComplete_l();
2456d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                } else {
246c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien                    mPlayer->seekToAsync(mStartupSeekTimeUs);
2476d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                }
2486d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
249c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien                mStartupSeekTimeUs = -1;
2506d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            }
2516d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            break;
252c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        }
2536d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2546d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_RUNNING:
255c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        {
2566d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            if (mAtEOS) {
2576d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                mPlayer->seekToAsync(0);
258c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien                mAtEOS = false;
2596d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                mPositionUs = -1;
2606d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            }
261c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            break;
2626d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        }
2636d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
264c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien        case STATE_PAUSED:
2656d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_STOPPED_AND_PREPARED:
2666d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        {
267c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien            if (mAtEOS) {
2686d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                mPlayer->seekToAsync(0);
2696d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                mAtEOS = false;
270c88ef135fcc2661ec7addc171ebc60787df38affRaph Levien                mPlayer->resume();
2716d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                mPositionUs = -1;
2726d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            } else {
2736d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                mPlayer->resume();
2746d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                if (mNotifyTimeRealUs != -1) {
2756d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                    // Pause time must be set if here by setPauseStartedTimeIfNeeded().
2766d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                    //CHECK(mPauseStartedTimeUs != -1);
2776d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2786d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                    // if no seek occurs, adjust our notify time so that getCurrentPosition()
2796d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                    // is continuous if read immediately after calling start().
2806d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                    mNotifyTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeUs;
2816d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien                }
2826d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            }
2836d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            break;
2846d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        }
2856d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2866d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        default:
2876d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            return INVALID_OPERATION;
2886d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    }
2896d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2906d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    mState = STATE_RUNNING;
2916d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    mPauseStartedTimeUs = -1;
2926d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2936d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    return OK;
2946d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien}
2956d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2966d15657e4a3826d4d47d5358f1dde211484527e9Raph Levienstatus_t NuPlayerDriver::stop() {
2976d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    Mutex::Autolock autoLock(mLock);
2986d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
2996d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien    switch (mState) {
3006d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_RUNNING:
3016d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mPlayer->pause();
3026d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            // fall through
3036d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
3046d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_PAUSED:
3056d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mState = STATE_STOPPED;
3066d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            notifyListener_l(MEDIA_STOPPED);
3076d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            break;
3086d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien
3096d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_PREPARED:
3106d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_STOPPED:
3116d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_STOPPED_AND_PREPARING:
3126d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien        case STATE_STOPPED_AND_PREPARED:
3136d15657e4a3826d4d47d5358f1dde211484527e9Raph Levien            mState = STATE_STOPPED;
314            break;
315
316        default:
317            return INVALID_OPERATION;
318    }
319    setPauseStartedTimeIfNeeded();
320
321    return OK;
322}
323
324status_t NuPlayerDriver::pause() {
325    Mutex::Autolock autoLock(mLock);
326
327    switch (mState) {
328        case STATE_PAUSED:
329        case STATE_PREPARED:
330            return OK;
331
332        case STATE_RUNNING:
333            setPauseStartedTimeIfNeeded();
334            mState = STATE_PAUSED;
335            notifyListener_l(MEDIA_PAUSED);
336            mPlayer->pause();
337            break;
338
339        default:
340            return INVALID_OPERATION;
341    }
342
343    return OK;
344}
345
346bool NuPlayerDriver::isPlaying() {
347    return mState == STATE_RUNNING && !mAtEOS;
348}
349
350status_t NuPlayerDriver::seekTo(int msec) {
351    Mutex::Autolock autoLock(mLock);
352
353    int64_t seekTimeUs = msec * 1000ll;
354
355    switch (mState) {
356        case STATE_PREPARED:
357        {
358            mStartupSeekTimeUs = seekTimeUs;
359            // pretend that the seek completed. It will actually happen when starting playback.
360            // TODO: actually perform the seek here, so the player is ready to go at the new
361            // location
362            notifySeekComplete_l();
363            break;
364        }
365
366        case STATE_RUNNING:
367        case STATE_PAUSED:
368        {
369            mAtEOS = false;
370            // seeks can take a while, so we essentially paused
371            notifyListener_l(MEDIA_PAUSED);
372            mPlayer->seekToAsync(seekTimeUs);
373            break;
374        }
375
376        default:
377            return INVALID_OPERATION;
378    }
379
380    mPositionUs = seekTimeUs;
381    mNotifyTimeRealUs = -1;
382    return OK;
383}
384
385status_t NuPlayerDriver::getCurrentPosition(int *msec) {
386    Mutex::Autolock autoLock(mLock);
387
388    if (mPositionUs < 0) {
389        // mPositionUs is the media time.
390        // It is negative under these cases
391        // (1) == -1 after reset, or very first playback, no stream notification yet.
392        // (2) == -1 start after end of stream, no stream notification yet.
393        // (3) == large negative # after ~292,471 years of continuous playback.
394
395        //CHECK_EQ(mPositionUs, -1);
396        *msec = 0;
397    } else if (mNotifyTimeRealUs == -1) {
398        // A seek has occurred just occurred, no stream notification yet.
399        // mPositionUs (>= 0) is the new media position.
400        *msec = mPositionUs / 1000;
401    } else {
402        // mPosition must be valid (i.e. >= 0) by the first check above.
403        // We're either playing or have pause time set: mPauseStartedTimeUs is >= 0
404        //LOG_ALWAYS_FATAL_IF(
405        //        !isPlaying() && mPauseStartedTimeUs < 0,
406        //        "Player in non-playing mState(%d) and mPauseStartedTimeUs(%lld) < 0",
407        //        mState, (long long)mPauseStartedTimeUs);
408        ALOG_ASSERT(mNotifyTimeRealUs >= 0);
409        int64_t nowUs =
410                (isPlaying() ?  ALooper::GetNowUs() : mPauseStartedTimeUs);
411        *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000;
412        // It is possible for *msec to be negative if the media position is > 596 hours.
413        // but we turn on this checking in NDEBUG == 0 mode.
414        ALOG_ASSERT(*msec >= 0);
415        ALOGV("getCurrentPosition nowUs(%lld)", (long long)nowUs);
416    }
417    ALOGV("getCurrentPosition returning(%d) mPositionUs(%lld) mNotifyRealTimeUs(%lld)",
418            *msec, (long long)mPositionUs, (long long)mNotifyTimeRealUs);
419    return OK;
420}
421
422status_t NuPlayerDriver::getDuration(int *msec) {
423    Mutex::Autolock autoLock(mLock);
424
425    if (mDurationUs < 0) {
426        return UNKNOWN_ERROR;
427    }
428
429    *msec = (mDurationUs + 500ll) / 1000;
430
431    return OK;
432}
433
434status_t NuPlayerDriver::reset() {
435    Mutex::Autolock autoLock(mLock);
436
437    switch (mState) {
438        case STATE_IDLE:
439            return OK;
440
441        case STATE_SET_DATASOURCE_PENDING:
442        case STATE_RESET_IN_PROGRESS:
443            return INVALID_OPERATION;
444
445        case STATE_PREPARING:
446        {
447            CHECK(mIsAsyncPrepare);
448
449            notifyListener_l(MEDIA_PREPARED);
450            break;
451        }
452
453        default:
454            break;
455    }
456
457    if (mState != STATE_STOPPED) {
458        notifyListener_l(MEDIA_STOPPED);
459    }
460
461    mState = STATE_RESET_IN_PROGRESS;
462    mPlayer->resetAsync();
463
464    while (mState == STATE_RESET_IN_PROGRESS) {
465        mCondition.wait(mLock);
466    }
467
468    mDurationUs = -1;
469    mPositionUs = -1;
470    mStartupSeekTimeUs = -1;
471    mLooping = false;
472
473    return OK;
474}
475
476status_t NuPlayerDriver::setLooping(int loop) {
477    mLooping = loop != 0;
478    return OK;
479}
480
481player_type NuPlayerDriver::playerType() {
482    return NU_PLAYER;
483}
484
485status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
486    if (reply == NULL) {
487        ALOGE("reply is a NULL pointer");
488        return BAD_VALUE;
489    }
490
491    int32_t methodId;
492    status_t ret = request.readInt32(&methodId);
493    if (ret != OK) {
494        ALOGE("Failed to retrieve the requested method to invoke");
495        return ret;
496    }
497
498    switch (methodId) {
499        case INVOKE_ID_SET_VIDEO_SCALING_MODE:
500        {
501            int mode = request.readInt32();
502            return mPlayer->setVideoScalingMode(mode);
503        }
504
505        case INVOKE_ID_GET_TRACK_INFO:
506        {
507            return mPlayer->getTrackInfo(reply);
508        }
509
510        case INVOKE_ID_SELECT_TRACK:
511        {
512            int trackIndex = request.readInt32();
513            return mPlayer->selectTrack(trackIndex, true /* select */);
514        }
515
516        case INVOKE_ID_UNSELECT_TRACK:
517        {
518            int trackIndex = request.readInt32();
519            return mPlayer->selectTrack(trackIndex, false /* select */);
520        }
521
522        case INVOKE_ID_GET_SELECTED_TRACK:
523        {
524            int32_t type = request.readInt32();
525            return mPlayer->getSelectedTrack(type, reply);
526        }
527
528        default:
529        {
530            return INVALID_OPERATION;
531        }
532    }
533}
534
535void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
536    mPlayer->setAudioSink(audioSink);
537    mAudioSink = audioSink;
538}
539
540status_t NuPlayerDriver::setParameter(
541        int /* key */, const Parcel & /* request */) {
542    return INVALID_OPERATION;
543}
544
545status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
546    return INVALID_OPERATION;
547}
548
549status_t NuPlayerDriver::getMetadata(
550        const media::Metadata::Filter& /* ids */, Parcel *records) {
551    Mutex::Autolock autoLock(mLock);
552
553    using media::Metadata;
554
555    Metadata meta(records);
556
557    meta.appendBool(
558            Metadata::kPauseAvailable,
559            mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
560
561    meta.appendBool(
562            Metadata::kSeekBackwardAvailable,
563            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
564
565    meta.appendBool(
566            Metadata::kSeekForwardAvailable,
567            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
568
569    meta.appendBool(
570            Metadata::kSeekAvailable,
571            mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
572
573    return OK;
574}
575
576void NuPlayerDriver::notifyResetComplete() {
577    Mutex::Autolock autoLock(mLock);
578
579    CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
580    mState = STATE_IDLE;
581    mCondition.broadcast();
582}
583
584void NuPlayerDriver::notifySetSurfaceComplete() {
585    Mutex::Autolock autoLock(mLock);
586
587    CHECK(mSetSurfaceInProgress);
588    mSetSurfaceInProgress = false;
589
590    mCondition.broadcast();
591}
592
593void NuPlayerDriver::notifyDuration(int64_t durationUs) {
594    Mutex::Autolock autoLock(mLock);
595    mDurationUs = durationUs;
596}
597
598void NuPlayerDriver::notifyPosition(int64_t positionUs) {
599    Mutex::Autolock autoLock(mLock);
600    if (isPlaying()) {
601        mPositionUs = positionUs;
602        mNotifyTimeRealUs = ALooper::GetNowUs();
603    }
604}
605
606void NuPlayerDriver::notifySeekComplete() {
607    Mutex::Autolock autoLock(mLock);
608    notifySeekComplete_l();
609}
610
611void NuPlayerDriver::notifySeekComplete_l() {
612    bool wasSeeking = true;
613    if (mState == STATE_STOPPED_AND_PREPARING) {
614        wasSeeking = false;
615        mState = STATE_STOPPED_AND_PREPARED;
616        mCondition.broadcast();
617        if (!mIsAsyncPrepare) {
618            // if we are preparing synchronously, no need to notify listener
619            return;
620        }
621    } else if (mState == STATE_STOPPED) {
622        // no need to notify listener
623        return;
624    }
625    notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
626}
627
628void NuPlayerDriver::notifyFrameStats(
629        int64_t numFramesTotal, int64_t numFramesDropped) {
630    Mutex::Autolock autoLock(mLock);
631    mNumFramesTotal = numFramesTotal;
632    mNumFramesDropped = numFramesDropped;
633}
634
635status_t NuPlayerDriver::dump(
636        int fd, const Vector<String16> & /* args */) const {
637    Mutex::Autolock autoLock(mLock);
638
639    FILE *out = fdopen(dup(fd), "w");
640
641    fprintf(out, " NuPlayer\n");
642    fprintf(out, "  numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), "
643                 "percentageDropped(%.2f)\n",
644                 mNumFramesTotal,
645                 mNumFramesDropped,
646                 mNumFramesTotal == 0
647                    ? 0.0 : (double)mNumFramesDropped / mNumFramesTotal);
648
649    fclose(out);
650    out = NULL;
651
652    return OK;
653}
654
655void NuPlayerDriver::notifyListener(
656        int msg, int ext1, int ext2, const Parcel *in) {
657    Mutex::Autolock autoLock(mLock);
658    notifyListener_l(msg, ext1, ext2, in);
659}
660
661void NuPlayerDriver::notifyListener_l(
662        int msg, int ext1, int ext2, const Parcel *in) {
663    switch (msg) {
664        case MEDIA_PLAYBACK_COMPLETE:
665        {
666            if (mState != STATE_RESET_IN_PROGRESS) {
667                if (mLooping || (mAutoLoop
668                        && (mAudioSink == NULL || mAudioSink->realtime()))) {
669                    mPlayer->seekToAsync(0);
670                    break;
671                }
672
673                mPlayer->pause();
674                mState = STATE_PAUSED;
675            }
676            // fall through
677        }
678
679        case MEDIA_ERROR:
680        {
681            mAtEOS = true;
682            setPauseStartedTimeIfNeeded();
683            break;
684        }
685
686        default:
687            break;
688    }
689
690    mLock.unlock();
691    sendEvent(msg, ext1, ext2, in);
692    mLock.lock();
693}
694
695void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
696    Mutex::Autolock autoLock(mLock);
697
698    CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
699
700    mAsyncResult = err;
701    mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
702    mCondition.broadcast();
703}
704
705void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
706    Mutex::Autolock autoLock(mLock);
707
708    if (mState != STATE_PREPARING) {
709        // We were preparing asynchronously when the client called
710        // reset(), we sent a premature "prepared" notification and
711        // then initiated the reset. This notification is stale.
712        CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
713        return;
714    }
715
716    CHECK_EQ(mState, STATE_PREPARING);
717
718    mAsyncResult = err;
719
720    if (err == OK) {
721        // update state before notifying client, so that if client calls back into NuPlayerDriver
722        // in response, NuPlayerDriver has the right state
723        mState = STATE_PREPARED;
724        if (mIsAsyncPrepare) {
725            notifyListener_l(MEDIA_PREPARED);
726        }
727    } else {
728        mState = STATE_UNPREPARED;
729        if (mIsAsyncPrepare) {
730            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
731        }
732    }
733
734    sp<MetaData> meta = mPlayer->getFileMeta();
735    int32_t loop;
736    if (meta != NULL
737            && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
738        mAutoLoop = true;
739    }
740
741    mCondition.broadcast();
742}
743
744void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
745    Mutex::Autolock autoLock(mLock);
746
747    mPlayerFlags = flags;
748}
749
750void NuPlayerDriver::setPauseStartedTimeIfNeeded() {
751    if (mPauseStartedTimeUs == -1) {
752        mPauseStartedTimeUs = ALooper::GetNowUs();
753    }
754}
755
756}  // namespace android
757