AwesomePlayer.cpp revision 1b78c4b1484c7d4c12b9a87329dc8d4b6e8c0c37
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
14163935113919a184122b8b3bd672ef08c8df65dcRomain Guy * limitations under the License.
15163935113919a184122b8b3bd672ef08c8df65dcRomain Guy */
16163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
17163935113919a184122b8b3bd672ef08c8df65dcRomain Guy#undef DEBUG_HDCP
181473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian
191473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian//#define LOG_NDEBUG 0
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "AwesomePlayer"
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define ATRACE_TAG ATRACE_TAG_VIDEO
22864c0d50cda714d73fa70e3600ec36b5db8a835aMathias Agopian#include <inttypes.h>
2366269ea6f68f2f25888ce1080c94ac782742fafcKenny Root#include <utils/Log.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Trace.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2669969e48f2bca9339662dddfacff0bbf6374ed7fDianne Hackborn#include <dlfcn.h>
276b1e838fc16d397359f82c3a4f5700f1ed7dd910Thomas Tafertshofer
281c4907ee77392afb768c2f088e0dedbe4239f6fbJack Palevich#include "include/AwesomePlayer.h"
291c4907ee77392afb768c2f088e0dedbe4239f6fbJack Palevich#include "include/DRMExtractor.h"
301c4907ee77392afb768c2f088e0dedbe4239f6fbJack Palevich#include "include/SoftwareRenderer.h"
311c4907ee77392afb768c2f088e0dedbe4239f6fbJack Palevich#include "include/NuCachedSource2.h"
32560814f6b11abe83ff0c4ed18cac015c276b3181Jack Palevich#include "include/ThrottledSource.h"
33d830e74ff4bc9aa015f746e54f6922bf5221f1baJesse Hall#include "include/MPEG2TSExtractor.h"
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "include/WVMExtractor.h"
35e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
36e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <binder/IPCThreadState.h>
37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <binder/IServiceManager.h>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/IMediaPlayerService.h>
39b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project#include <media/stagefright/foundation/hexdump.h>
400a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include <media/stagefright/foundation/ADebug.h>
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/timedtext/TimedTextDriver.h>
423866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian#include <media/stagefright/AudioPlayer.h>
4364a55af0ac700baecb0877235eb42caac59a3560Jeff Brown#include <media/stagefright/ClockEstimator.h>
448f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy#include <media/stagefright/DataSource.h>
4546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include <media/stagefright/FileSource.h>
469f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#include <media/stagefright/MediaBuffer.h>
4732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include <media/stagefright/MediaDefs.h>
48c28867a1d67121ce5963de135e3ae2b1dbd9a33dJeff Brown#include <media/stagefright/MediaExtractor.h>
4946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include <media/stagefright/MediaSource.h>
5049ed71db425c5054e3ad9526496a7e116c89556bJeff Brown#include <media/stagefright/MetaData.h>
51a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy#include <media/stagefright/OMXCodec.h>
52a1cff5043d0fbd78fcf9c48e7658e56a5b0c2de3Chet Haase#include <media/stagefright/Utils.h>
53e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
5446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include <gui/IGraphicBufferProducer.h>
552352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown#include <gui/Surface.h>
562ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/AMessage.h>
58dae8e94cce0881f3e10ef5e34b881f512bb52a75Doug Felt
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/properties.h>
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define USE_SURFACE_ALLOC 1
62fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate#define FRAME_DROP_FREQ 0
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64d84e1ce0b535128f03416145554fb405f9fade3eJeff Sharkeynamespace android {
65c07fca3831baf4d812dd724f506b4ed23dcc39e0Stephen Smalley
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int64_t kHighWaterMarkUs = 5000000ll;  // 5secs
68481c1570dc5cdf58265b53f657801709dd05d1dfJeff Brownstatic const size_t kLowWaterMarkBytes = 40000;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic const size_t kHighWaterMarkBytes = 200000;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer
722b4abcd0c7c4361af8ab6d5d7b073fb75ac6d219Dan Egnor// is destroyed to allow the audio DSP to power down.
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int64_t kOffloadPauseMaxUs = 60000000ll;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct AwesomeEvent : public TimedEventQueue::Event {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AwesomeEvent(
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            AwesomePlayer *player,
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            void (AwesomePlayer::*method)())
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        : mPlayer(player),
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project          mMethod(method) {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
84f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph Wenprotected:
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual ~AwesomeEvent() {}
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void fire(TimedEventQueue * /* queue */, int64_t /* now_us */) {
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        (mPlayer->*mMethod)();
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprivate:
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AwesomePlayer *mPlayer;
93aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    void (AwesomePlayer::*mMethod)();
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AwesomeEvent(const AwesomeEvent &);
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AwesomeEvent &operator=(const AwesomeEvent &);
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct AwesomeLocalRenderer : public AwesomeRenderer {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AwesomeLocalRenderer(
101a06d86ab8177ee9e631e0ee4e39688bf42179bdeLeon Scroggins            const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void render(MediaBuffer *buffer) {
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        render((const uint8_t *)buffer->data() + buffer->range_offset(),
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               buffer->range_length());
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1096b849e2123be98eb2a1a25b8abf0b13a279ce952Wei-Ta Chen
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void render(const void *data, size_t size) {
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTarget->render(data, size, NULL);
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1136714efc5e0c52953b65e774de0003e22377e7d39Jamie Gennis
114f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Feltprotected:
115d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio    virtual ~AwesomeLocalRenderer() {
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        delete mTarget;
1176b849e2123be98eb2a1a25b8abf0b13a279ce952Wei-Ta Chen        mTarget = NULL;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
119bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprivate:
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SoftwareRenderer *mTarget;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AwesomeLocalRenderer(const AwesomeLocalRenderer &);
124cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct AwesomeNativeWindowRenderer : public AwesomeRenderer {
128b01e8bf57b7492b77e3445db51471edcbadda75eMike Lockwood    AwesomeNativeWindowRenderer(
129e7d511e148bc901ef41ac44d7b3593e5d803f72fMike Lockwood            const sp<ANativeWindow> &nativeWindow,
130acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood            int32_t rotationDegrees)
131e7d511e148bc901ef41ac44d7b3593e5d803f72fMike Lockwood        : mNativeWindow(nativeWindow) {
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        applyRotation(rotationDegrees);
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void render(MediaBuffer *buffer) {
13698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall        ATRACE_CALL();
137ecaa7b41ca49154ceaa9a7504eb0a86b89a96026Christopher Tate        int64_t timeUs;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);
1401cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato        status_t err = mNativeWindow->queueBuffer(
141d2110dbce071a236b6176de344ca797b737542ebJoe Onorato                mNativeWindow.get(), buffer->graphicBuffer().get(), -1);
1424ababd922eac5931e0222862ff082dc29e012816Joe Onorato        if (err != 0) {
14302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),
1444a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate                    -err);
14508d5b8fad8d46ccb64db2fdcb4d66972ec87bf48Dianne Hackborn            return;
1466e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase        }
1479a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey
1489a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey        sp<MetaData> metaData = buffer->meta_data();
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        metaData->setInt32(kKeyRendered, 1);
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprotected:
153e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    virtual ~AwesomeNativeWindowRenderer() {}
15408965ec67ada98f63f8ac879cc44c8b0e7ff046dMathias Agopian
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprivate:
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sp<ANativeWindow> mNativeWindow;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1589a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey    void applyRotation(int32_t rotationDegrees) {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        uint32_t transform;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (rotationDegrees) {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0: transform = 0; break;
162517f67fe4b70c5a1907cb503d62b906a1eed2e1eBilly Hewlett            case 90: transform = HAL_TRANSFORM_ROT_90; break;
163ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger            case 180: transform = HAL_TRANSFORM_ROT_180; break;
164d81ec456bb097a712bcbc093c5a1e0075434158eDerek Sollenberger            case 270: transform = HAL_TRANSFORM_ROT_270; break;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default: transform = 0; break;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (transform) {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            CHECK_EQ(0, native_window_set_buffers_transform(
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mNativeWindow.get(), transform));
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
173bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
174aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
17566269ea6f68f2f25888ce1080c94ac782742fafcKenny Root    AwesomeNativeWindowRenderer &operator=(
17669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes            const AwesomeNativeWindowRenderer &);
17769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes};
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// To collect the decoder usage
18083c64e6b624a876436d2ef5d2f173b10407e27b4Mathias Agopianvoid addBatteryData(uint32_t params) {
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sp<IBinder> binder =
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        defaultServiceManager()->getService(String16("media.player"));
183d685894212e6dbeac1fda4996903c1da115d49a6Ying Wang    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CHECK(service.get() != NULL);
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18625ba5b6564224dceefa086b5c439ef28dad530caMathias Agopian    service->addBatteryData(params);
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1891bf797857e025e8a71db86fb9e79765a767ec1ebMathias Agopian////////////////////////////////////////////////////////////////////////////////
190000479f9e325b4e426a67033abd92d47da412725Mathias AgopianAwesomePlayer::AwesomePlayer()
191b5af325fb1d21a9295bf3009cc95e5ead4999247Mike Reed    : mQueueStarted(false),
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mUIDValid(false),
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mTimeSource(NULL),
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mVideoRenderingStarted(false),
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mVideoRendererIsPreview(false),
196560814f6b11abe83ff0c4ed18cac015c276b3181Jack Palevich      mMediaRenderingStartGeneration(0),
197a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich      mStartGeneration(0),
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mAudioPlayer(NULL),
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mDisplayWidth(0),
200c9a1aabc49d31370e3bf41f85b805499640230b1Kenny Root      mDisplayHeight(0),
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mFlags(0),
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mExtractorFlags(0),
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mVideoBuffer(NULL),
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mDecryptHandle(NULL),
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mLastVideoTimeUs(-1),
207bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen      mTextDriver(NULL),
208cd0e839a2448deea50f79bddeba782c546b33893Nick Pelly      mOffloadAudio(false),
209e7d511e148bc901ef41ac44d7b3593e5d803f72fMike Lockwood      mAudioTearDown(false) {
210aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien    CHECK_EQ(mClient.connect(), (status_t)OK);
2117304c343821309dd15f769b18f1de2fa43751573Jeff Brown
212755fd617258d3f1731b2829d681cab680db0fdd5Mike Lockwood    DataSource::RegisterDefaultSniffers();
213163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
214163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
215163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    mVideoEventPending = false;
216163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mStreamDoneEventPending = false;
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
219bd882b1c8708686d373c56e07e6bb8b1cb6ffd9eJeff Brown    mBufferingEventPending = false;
220bd882b1c8708686d373c56e07e6bb8b1cb6ffd9eJeff Brown    mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
221bd882b1c8708686d373c56e07e6bb8b1cb6ffd9eJeff Brown    mVideoLagEventPending = false;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCheckAudioStatusEvent = new AwesomeEvent(
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this, &AwesomePlayer::onCheckAudioStatus);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mAudioStatusEventPending = false;
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mAudioTearDownEvent = new AwesomeEvent(this,
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              &AwesomePlayer::onAudioTearDownEvent);
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mAudioTearDownEventPending = false;
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mClockEstimator = new WindowedLinearFitEstimator();
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
234    reset();
235}
236
237AwesomePlayer::~AwesomePlayer() {
238    if (mQueueStarted) {
239        mQueue.stop();
240    }
241
242    reset();
243
244    mClient.disconnect();
245}
246
247void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) {
248    mQueue.cancelEvent(mVideoEvent->eventID());
249    mVideoEventPending = false;
250    mQueue.cancelEvent(mVideoLagEvent->eventID());
251    mVideoLagEventPending = false;
252
253    if (mOffloadAudio) {
254        mQueue.cancelEvent(mAudioTearDownEvent->eventID());
255        mAudioTearDownEventPending = false;
256    }
257
258    if (!keepNotifications) {
259        mQueue.cancelEvent(mStreamDoneEvent->eventID());
260        mStreamDoneEventPending = false;
261        mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
262        mAudioStatusEventPending = false;
263
264        mQueue.cancelEvent(mBufferingEvent->eventID());
265        mBufferingEventPending = false;
266        mAudioTearDown = false;
267    }
268}
269
270void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
271    Mutex::Autolock autoLock(mLock);
272    mListener = listener;
273}
274
275void AwesomePlayer::setUID(uid_t uid) {
276    ALOGV("AwesomePlayer running on behalf of uid %d", uid);
277
278    mUID = uid;
279    mUIDValid = true;
280}
281
282status_t AwesomePlayer::setDataSource(
283        const char *uri, const KeyedVector<String8, String8> *headers) {
284    Mutex::Autolock autoLock(mLock);
285    return setDataSource_l(uri, headers);
286}
287
288status_t AwesomePlayer::setDataSource_l(
289        const char *uri, const KeyedVector<String8, String8> *headers) {
290    reset_l();
291
292    mUri = uri;
293
294    if (headers) {
295        mUriHeaders = *headers;
296
297        ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
298        if (index >= 0) {
299            // Browser is in "incognito" mode, suppress logging URLs.
300
301            // This isn't something that should be passed to the server.
302            mUriHeaders.removeItemsAt(index);
303
304            modifyFlags(INCOGNITO, SET);
305        }
306    }
307
308    ALOGI("setDataSource_l(URL suppressed)");
309
310    // The actual work will be done during preparation in the call to
311    // ::finishSetDataSource_l to avoid blocking the calling thread in
312    // setDataSource for any significant time.
313
314    {
315        Mutex::Autolock autoLock(mStatsLock);
316        mStats.mFd = -1;
317        mStats.mURI = mUri;
318    }
319
320    return OK;
321}
322
323status_t AwesomePlayer::setDataSource(
324        int fd, int64_t offset, int64_t length) {
325    Mutex::Autolock autoLock(mLock);
326
327    reset_l();
328
329    sp<DataSource> dataSource = new FileSource(fd, offset, length);
330
331    status_t err = dataSource->initCheck();
332
333    if (err != OK) {
334        return err;
335    }
336
337    mFileSource = dataSource;
338
339    {
340        Mutex::Autolock autoLock(mStatsLock);
341        mStats.mFd = fd;
342        mStats.mURI = String8();
343    }
344
345    return setDataSource_l(dataSource);
346}
347
348status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) {
349    return INVALID_OPERATION;
350}
351
352status_t AwesomePlayer::setDataSource_l(
353        const sp<DataSource> &dataSource) {
354    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
355
356    if (extractor == NULL) {
357        return UNKNOWN_ERROR;
358    }
359
360    if (extractor->getDrmFlag()) {
361        checkDrmStatus(dataSource);
362    }
363
364    return setDataSource_l(extractor);
365}
366
367void AwesomePlayer::checkDrmStatus(const sp<DataSource>& dataSource) {
368    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
369    if (mDecryptHandle != NULL) {
370        CHECK(mDrmManagerClient);
371        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
372            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
373        }
374    }
375}
376
377status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
378    // Attempt to approximate overall stream bitrate by summing all
379    // tracks' individual bitrates, if not all of them advertise bitrate,
380    // we have to fail.
381
382    int64_t totalBitRate = 0;
383
384    mExtractor = extractor;
385    for (size_t i = 0; i < extractor->countTracks(); ++i) {
386        sp<MetaData> meta = extractor->getTrackMetaData(i);
387
388        int32_t bitrate;
389        if (!meta->findInt32(kKeyBitRate, &bitrate)) {
390            const char *mime;
391            CHECK(meta->findCString(kKeyMIMEType, &mime));
392            ALOGV("track of type '%s' does not publish bitrate", mime);
393
394            totalBitRate = -1;
395            break;
396        }
397
398        totalBitRate += bitrate;
399    }
400
401    mBitrate = totalBitRate;
402
403    ALOGV("mBitrate = %lld bits/sec", mBitrate);
404
405    {
406        Mutex::Autolock autoLock(mStatsLock);
407        mStats.mBitrate = mBitrate;
408        mStats.mTracks.clear();
409        mStats.mAudioTrackIndex = -1;
410        mStats.mVideoTrackIndex = -1;
411    }
412
413    bool haveAudio = false;
414    bool haveVideo = false;
415    for (size_t i = 0; i < extractor->countTracks(); ++i) {
416        sp<MetaData> meta = extractor->getTrackMetaData(i);
417
418        const char *_mime;
419        CHECK(meta->findCString(kKeyMIMEType, &_mime));
420
421        String8 mime = String8(_mime);
422
423        if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {
424            setVideoSource(extractor->getTrack(i));
425            haveVideo = true;
426
427            // Set the presentation/display size
428            int32_t displayWidth, displayHeight;
429            bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
430            if (success) {
431                success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
432            }
433            if (success) {
434                mDisplayWidth = displayWidth;
435                mDisplayHeight = displayHeight;
436            }
437
438            {
439                Mutex::Autolock autoLock(mStatsLock);
440                mStats.mVideoTrackIndex = mStats.mTracks.size();
441                mStats.mTracks.push();
442                TrackStat *stat =
443                    &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
444                stat->mMIME = mime.string();
445            }
446        } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {
447            setAudioSource(extractor->getTrack(i));
448            haveAudio = true;
449            mActiveAudioTrackIndex = i;
450
451            {
452                Mutex::Autolock autoLock(mStatsLock);
453                mStats.mAudioTrackIndex = mStats.mTracks.size();
454                mStats.mTracks.push();
455                TrackStat *stat =
456                    &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
457                stat->mMIME = mime.string();
458            }
459
460            if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) {
461                // Only do this for vorbis audio, none of the other audio
462                // formats even support this ringtone specific hack and
463                // retrieving the metadata on some extractors may turn out
464                // to be very expensive.
465                sp<MetaData> fileMeta = extractor->getMetaData();
466                int32_t loop;
467                if (fileMeta != NULL
468                        && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
469                    modifyFlags(AUTO_LOOPING, SET);
470                }
471            }
472        } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
473            addTextSource_l(i, extractor->getTrack(i));
474        }
475    }
476
477    if (!haveAudio && !haveVideo) {
478        if (mWVMExtractor != NULL) {
479            return mWVMExtractor->getError();
480        } else {
481            return UNKNOWN_ERROR;
482        }
483    }
484
485    mExtractorFlags = extractor->flags();
486
487    return OK;
488}
489
490void AwesomePlayer::reset() {
491    Mutex::Autolock autoLock(mLock);
492    reset_l();
493}
494
495void AwesomePlayer::reset_l() {
496    mVideoRenderingStarted = false;
497    mActiveAudioTrackIndex = -1;
498    mDisplayWidth = 0;
499    mDisplayHeight = 0;
500
501    notifyListener_l(MEDIA_STOPPED);
502
503    if (mDecryptHandle != NULL) {
504            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
505                    Playback::STOP, 0);
506            mDecryptHandle = NULL;
507            mDrmManagerClient = NULL;
508    }
509
510    if (mFlags & PLAYING) {
511        uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
512        if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
513            params |= IMediaPlayerService::kBatteryDataTrackAudio;
514        }
515        if (mVideoSource != NULL) {
516            params |= IMediaPlayerService::kBatteryDataTrackVideo;
517        }
518        addBatteryData(params);
519    }
520
521    if (mFlags & PREPARING) {
522        modifyFlags(PREPARE_CANCELLED, SET);
523        if (mConnectingDataSource != NULL) {
524            ALOGI("interrupting the connection process");
525            mConnectingDataSource->disconnect();
526        }
527
528        if (mFlags & PREPARING_CONNECTED) {
529            // We are basically done preparing, we're just buffering
530            // enough data to start playback, we can safely interrupt that.
531            finishAsyncPrepare_l();
532        }
533    }
534
535    while (mFlags & PREPARING) {
536        mPreparedCondition.wait(mLock);
537    }
538
539    cancelPlayerEvents();
540
541    mWVMExtractor.clear();
542    mCachedSource.clear();
543    mAudioTrack.clear();
544    mVideoTrack.clear();
545    mExtractor.clear();
546
547    // Shutdown audio first, so that the response to the reset request
548    // appears to happen instantaneously as far as the user is concerned
549    // If we did this later, audio would continue playing while we
550    // shutdown the video-related resources and the player appear to
551    // not be as responsive to a reset request.
552    if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
553            && mAudioSource != NULL) {
554        // If we had an audio player, it would have effectively
555        // taken possession of the audio source and stopped it when
556        // _it_ is stopped. Otherwise this is still our responsibility.
557        mAudioSource->stop();
558    }
559    mAudioSource.clear();
560    mOmxSource.clear();
561
562    mTimeSource = NULL;
563
564    delete mAudioPlayer;
565    mAudioPlayer = NULL;
566
567    if (mTextDriver != NULL) {
568        delete mTextDriver;
569        mTextDriver = NULL;
570    }
571
572    mVideoRenderer.clear();
573
574    if (mVideoSource != NULL) {
575        shutdownVideoDecoder_l();
576    }
577
578    mDurationUs = -1;
579    modifyFlags(0, ASSIGN);
580    mExtractorFlags = 0;
581    mTimeSourceDeltaUs = 0;
582    mVideoTimeUs = 0;
583
584    mSeeking = NO_SEEK;
585    mSeekNotificationSent = true;
586    mSeekTimeUs = 0;
587
588    mUri.setTo("");
589    mUriHeaders.clear();
590
591    mFileSource.clear();
592
593    mBitrate = -1;
594    mLastVideoTimeUs = -1;
595
596    {
597        Mutex::Autolock autoLock(mStatsLock);
598        mStats.mFd = -1;
599        mStats.mURI = String8();
600        mStats.mBitrate = -1;
601        mStats.mAudioTrackIndex = -1;
602        mStats.mVideoTrackIndex = -1;
603        mStats.mNumVideoFramesDecoded = 0;
604        mStats.mNumVideoFramesDropped = 0;
605        mStats.mVideoWidth = -1;
606        mStats.mVideoHeight = -1;
607        mStats.mFlags = 0;
608        mStats.mTracks.clear();
609    }
610
611    mWatchForAudioSeekComplete = false;
612    mWatchForAudioEOS = false;
613
614    mMediaRenderingStartGeneration = 0;
615    mStartGeneration = 0;
616}
617
618void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
619    if ((mListener != NULL) && !mAudioTearDown) {
620        sp<MediaPlayerBase> listener = mListener.promote();
621
622        if (listener != NULL) {
623            listener->sendEvent(msg, ext1, ext2);
624        }
625    }
626}
627
628bool AwesomePlayer::getBitrate(int64_t *bitrate) {
629    off64_t size;
630    if (mDurationUs > 0 && mCachedSource != NULL
631            && mCachedSource->getSize(&size) == OK) {
632        *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
633        return true;
634    }
635
636    if (mBitrate >= 0) {
637        *bitrate = mBitrate;
638        return true;
639    }
640
641    *bitrate = 0;
642
643    return false;
644}
645
646// Returns true iff cached duration is available/applicable.
647bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
648    int64_t bitrate;
649
650    if (mCachedSource != NULL && getBitrate(&bitrate) && (bitrate > 0)) {
651        status_t finalStatus;
652        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
653        *durationUs = cachedDataRemaining * 8000000ll / bitrate;
654        *eos = (finalStatus != OK);
655        return true;
656    } else if (mWVMExtractor != NULL) {
657        status_t finalStatus;
658        *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus);
659        *eos = (finalStatus != OK);
660        return true;
661    }
662
663    return false;
664}
665
666void AwesomePlayer::ensureCacheIsFetching_l() {
667    if (mCachedSource != NULL) {
668        mCachedSource->resumeFetchingIfNecessary();
669    }
670}
671
672void AwesomePlayer::onVideoLagUpdate() {
673    Mutex::Autolock autoLock(mLock);
674    if (!mVideoLagEventPending) {
675        return;
676    }
677    mVideoLagEventPending = false;
678
679    int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
680    int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
681
682    if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
683        ALOGV("video late by %lld ms.", videoLateByUs / 1000ll);
684
685        notifyListener_l(
686                MEDIA_INFO,
687                MEDIA_INFO_VIDEO_TRACK_LAGGING,
688                videoLateByUs / 1000ll);
689    }
690
691    postVideoLagEvent_l();
692}
693
694void AwesomePlayer::onBufferingUpdate() {
695    Mutex::Autolock autoLock(mLock);
696    if (!mBufferingEventPending) {
697        return;
698    }
699    mBufferingEventPending = false;
700
701    if (mCachedSource != NULL) {
702        status_t finalStatus;
703        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
704        bool eos = (finalStatus != OK);
705
706        if (eos) {
707            if (finalStatus == ERROR_END_OF_STREAM) {
708                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
709            }
710            if (mFlags & PREPARING) {
711                ALOGV("cache has reached EOS, prepare is done.");
712                finishAsyncPrepare_l();
713            }
714        } else {
715            int64_t bitrate;
716            if (getBitrate(&bitrate)) {
717                size_t cachedSize = mCachedSource->cachedSize();
718                int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
719
720                int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
721                if (percentage > 100) {
722                    percentage = 100;
723                }
724
725                notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
726            } else {
727                // We don't know the bitrate of the stream, use absolute size
728                // limits to maintain the cache.
729
730                if ((mFlags & PLAYING) && !eos
731                        && (cachedDataRemaining < kLowWaterMarkBytes)) {
732                    ALOGI("cache is running low (< %zu) , pausing.",
733                         kLowWaterMarkBytes);
734                    modifyFlags(CACHE_UNDERRUN, SET);
735                    pause_l();
736                    ensureCacheIsFetching_l();
737                    sendCacheStats();
738                    notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
739                } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
740                    if (mFlags & CACHE_UNDERRUN) {
741                        ALOGI("cache has filled up (> %zu), resuming.",
742                             kHighWaterMarkBytes);
743                        modifyFlags(CACHE_UNDERRUN, CLEAR);
744                        play_l();
745                    } else if (mFlags & PREPARING) {
746                        ALOGV("cache has filled up (> %zu), prepare is done",
747                             kHighWaterMarkBytes);
748                        finishAsyncPrepare_l();
749                    }
750                }
751            }
752        }
753    } else if (mWVMExtractor != NULL) {
754        status_t finalStatus;
755
756        int64_t cachedDurationUs
757            = mWVMExtractor->getCachedDurationUs(&finalStatus);
758
759        bool eos = (finalStatus != OK);
760
761        if (eos) {
762            if (finalStatus == ERROR_END_OF_STREAM) {
763                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
764            }
765            if (mFlags & PREPARING) {
766                ALOGV("cache has reached EOS, prepare is done.");
767                finishAsyncPrepare_l();
768            }
769        } else {
770            int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
771            if (percentage > 100) {
772                percentage = 100;
773            }
774
775            notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
776        }
777    }
778
779    int64_t cachedDurationUs;
780    bool eos;
781    if (getCachedDuration_l(&cachedDurationUs, &eos)) {
782        ALOGV("cachedDurationUs = %.2f secs, eos=%d",
783             cachedDurationUs / 1E6, eos);
784
785        if ((mFlags & PLAYING) && !eos
786                && (cachedDurationUs < kLowWaterMarkUs)) {
787            modifyFlags(CACHE_UNDERRUN, SET);
788            ALOGI("cache is running low (%.2f secs) , pausing.",
789                  cachedDurationUs / 1E6);
790            pause_l();
791            ensureCacheIsFetching_l();
792            sendCacheStats();
793            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
794        } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
795            if (mFlags & CACHE_UNDERRUN) {
796                modifyFlags(CACHE_UNDERRUN, CLEAR);
797                ALOGI("cache has filled up (%.2f secs), resuming.",
798                      cachedDurationUs / 1E6);
799                play_l();
800            } else if (mFlags & PREPARING) {
801                ALOGV("cache has filled up (%.2f secs), prepare is done",
802                     cachedDurationUs / 1E6);
803                finishAsyncPrepare_l();
804            }
805        }
806    }
807
808    if (mFlags & (PLAYING | PREPARING | CACHE_UNDERRUN)) {
809        postBufferingEvent_l();
810    }
811}
812
813void AwesomePlayer::sendCacheStats() {
814    sp<MediaPlayerBase> listener = mListener.promote();
815    if (listener != NULL) {
816        int32_t kbps = 0;
817        status_t err = UNKNOWN_ERROR;
818        if (mCachedSource != NULL) {
819            err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
820        } else if (mWVMExtractor != NULL) {
821            err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
822        }
823        if (err == OK) {
824            listener->sendEvent(
825                MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps);
826        }
827    }
828}
829
830void AwesomePlayer::onStreamDone() {
831    // Posted whenever any stream finishes playing.
832    ATRACE_CALL();
833
834    Mutex::Autolock autoLock(mLock);
835    if (!mStreamDoneEventPending) {
836        return;
837    }
838    mStreamDoneEventPending = false;
839
840    if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
841        ALOGV("MEDIA_ERROR %d", mStreamDoneStatus);
842
843        notifyListener_l(
844                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
845
846        pause_l(true /* at eos */);
847
848        modifyFlags(AT_EOS, SET);
849        return;
850    }
851
852    const bool allDone =
853        (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
854            && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
855
856    if (!allDone) {
857        return;
858    }
859
860    if ((mFlags & LOOPING)
861            || ((mFlags & AUTO_LOOPING)
862                && (mAudioSink == NULL || mAudioSink->realtime()))) {
863        // Don't AUTO_LOOP if we're being recorded, since that cannot be
864        // turned off and recording would go on indefinitely.
865
866        seekTo_l(0);
867
868        if (mVideoSource != NULL) {
869            postVideoEvent_l();
870        }
871    } else {
872        ALOGV("MEDIA_PLAYBACK_COMPLETE");
873        notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
874
875        pause_l(true /* at eos */);
876
877        // If audio hasn't completed MEDIA_SEEK_COMPLETE yet,
878        // notify MEDIA_SEEK_COMPLETE to observer immediately for state persistence.
879        if (mWatchForAudioSeekComplete) {
880            notifyListener_l(MEDIA_SEEK_COMPLETE);
881            mWatchForAudioSeekComplete = false;
882        }
883
884        modifyFlags(AT_EOS, SET);
885    }
886}
887
888status_t AwesomePlayer::play() {
889    ATRACE_CALL();
890
891    Mutex::Autolock autoLock(mLock);
892
893    modifyFlags(CACHE_UNDERRUN, CLEAR);
894
895    return play_l();
896}
897
898status_t AwesomePlayer::play_l() {
899    modifyFlags(SEEK_PREVIEW, CLEAR);
900
901    if (mFlags & PLAYING) {
902        return OK;
903    }
904
905    mMediaRenderingStartGeneration = ++mStartGeneration;
906
907    if (!(mFlags & PREPARED)) {
908        status_t err = prepare_l();
909
910        if (err != OK) {
911            return err;
912        }
913    }
914
915    modifyFlags(PLAYING, SET);
916    modifyFlags(FIRST_FRAME, SET);
917
918    if (mDecryptHandle != NULL) {
919        int64_t position;
920        getPosition(&position);
921        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
922                Playback::START, position / 1000);
923    }
924
925    if (mAudioSource != NULL) {
926        if (mAudioPlayer == NULL) {
927            createAudioPlayer_l();
928        }
929
930        CHECK(!(mFlags & AUDIO_RUNNING));
931
932        if (mVideoSource == NULL) {
933
934            // We don't want to post an error notification at this point,
935            // the error returned from MediaPlayer::start() will suffice.
936
937            status_t err = startAudioPlayer_l(
938                    false /* sendErrorNotification */);
939
940            if ((err != OK) && mOffloadAudio) {
941                ALOGI("play_l() cannot create offload output, fallback to sw decode");
942                int64_t curTimeUs;
943                getPosition(&curTimeUs);
944
945                delete mAudioPlayer;
946                mAudioPlayer = NULL;
947                // if the player was started it will take care of stopping the source when destroyed
948                if (!(mFlags & AUDIOPLAYER_STARTED)) {
949                    mAudioSource->stop();
950                }
951                modifyFlags((AUDIO_RUNNING | AUDIOPLAYER_STARTED), CLEAR);
952                mOffloadAudio = false;
953                mAudioSource = mOmxSource;
954                if (mAudioSource != NULL) {
955                    err = mAudioSource->start();
956
957                    if (err != OK) {
958                        mAudioSource.clear();
959                    } else {
960                        mSeekNotificationSent = true;
961                        if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
962                            seekTo_l(curTimeUs);
963                        }
964                        createAudioPlayer_l();
965                        err = startAudioPlayer_l(false);
966                    }
967                }
968            }
969
970            if (err != OK) {
971                delete mAudioPlayer;
972                mAudioPlayer = NULL;
973
974                modifyFlags((PLAYING | FIRST_FRAME), CLEAR);
975
976                if (mDecryptHandle != NULL) {
977                    mDrmManagerClient->setPlaybackStatus(
978                            mDecryptHandle, Playback::STOP, 0);
979                }
980
981                return err;
982            }
983        }
984    }
985
986    if (mTimeSource == NULL && mAudioPlayer == NULL) {
987        mTimeSource = &mSystemTimeSource;
988    }
989
990    if (mVideoSource != NULL) {
991        // Kick off video playback
992        postVideoEvent_l();
993
994        if (mAudioSource != NULL && mVideoSource != NULL) {
995            postVideoLagEvent_l();
996        }
997    }
998
999    if (mFlags & AT_EOS) {
1000        // Legacy behaviour, if a stream finishes playing and then
1001        // is started again, we play from the start...
1002        seekTo_l(0);
1003    }
1004
1005    uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
1006        | IMediaPlayerService::kBatteryDataTrackDecoder;
1007    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
1008        params |= IMediaPlayerService::kBatteryDataTrackAudio;
1009    }
1010    if (mVideoSource != NULL) {
1011        params |= IMediaPlayerService::kBatteryDataTrackVideo;
1012    }
1013    addBatteryData(params);
1014
1015    if (isStreamingHTTP()) {
1016        postBufferingEvent_l();
1017    }
1018
1019    return OK;
1020}
1021
1022void AwesomePlayer::createAudioPlayer_l()
1023{
1024    uint32_t flags = 0;
1025    int64_t cachedDurationUs;
1026    bool eos;
1027
1028    if (mOffloadAudio) {
1029        flags |= AudioPlayer::USE_OFFLOAD;
1030    } else if (mVideoSource == NULL
1031            && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US ||
1032            (getCachedDuration_l(&cachedDurationUs, &eos) &&
1033            cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) {
1034        flags |= AudioPlayer::ALLOW_DEEP_BUFFERING;
1035    }
1036    if (isStreamingHTTP()) {
1037        flags |= AudioPlayer::IS_STREAMING;
1038    }
1039    if (mVideoSource != NULL) {
1040        flags |= AudioPlayer::HAS_VIDEO;
1041    }
1042
1043    mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
1044    mAudioPlayer->setSource(mAudioSource);
1045
1046    mTimeSource = mAudioPlayer;
1047
1048    // If there was a seek request before we ever started,
1049    // honor the request now.
1050    // Make sure to do this before starting the audio player
1051    // to avoid a race condition.
1052    seekAudioIfNecessary_l();
1053}
1054
1055void AwesomePlayer::notifyIfMediaStarted_l() {
1056    if (mMediaRenderingStartGeneration == mStartGeneration) {
1057        mMediaRenderingStartGeneration = -1;
1058        notifyListener_l(MEDIA_STARTED);
1059    }
1060}
1061
1062status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) {
1063    CHECK(!(mFlags & AUDIO_RUNNING));
1064    status_t err = OK;
1065
1066    if (mAudioSource == NULL || mAudioPlayer == NULL) {
1067        return OK;
1068    }
1069
1070    if (mOffloadAudio) {
1071        mQueue.cancelEvent(mAudioTearDownEvent->eventID());
1072        mAudioTearDownEventPending = false;
1073    }
1074
1075    if (!(mFlags & AUDIOPLAYER_STARTED)) {
1076        bool wasSeeking = mAudioPlayer->isSeeking();
1077
1078        // We've already started the MediaSource in order to enable
1079        // the prefetcher to read its data.
1080        err = mAudioPlayer->start(
1081                true /* sourceAlreadyStarted */);
1082
1083        if (err != OK) {
1084            if (sendErrorNotification) {
1085                notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1086            }
1087
1088            return err;
1089        }
1090
1091        modifyFlags(AUDIOPLAYER_STARTED, SET);
1092
1093        if (wasSeeking) {
1094            CHECK(!mAudioPlayer->isSeeking());
1095
1096            // We will have finished the seek while starting the audio player.
1097            postAudioSeekComplete();
1098        } else {
1099            notifyIfMediaStarted_l();
1100        }
1101    } else {
1102        err = mAudioPlayer->resume();
1103    }
1104
1105    if (err == OK) {
1106        modifyFlags(AUDIO_RUNNING, SET);
1107
1108        mWatchForAudioEOS = true;
1109    }
1110
1111    return err;
1112}
1113
1114void AwesomePlayer::notifyVideoSize_l() {
1115    ATRACE_CALL();
1116    sp<MetaData> meta = mVideoSource->getFormat();
1117
1118    int32_t cropLeft, cropTop, cropRight, cropBottom;
1119    if (!meta->findRect(
1120                kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
1121        int32_t width, height;
1122        CHECK(meta->findInt32(kKeyWidth, &width));
1123        CHECK(meta->findInt32(kKeyHeight, &height));
1124
1125        cropLeft = cropTop = 0;
1126        cropRight = width - 1;
1127        cropBottom = height - 1;
1128
1129        ALOGV("got dimensions only %d x %d", width, height);
1130    } else {
1131        ALOGV("got crop rect %d, %d, %d, %d",
1132             cropLeft, cropTop, cropRight, cropBottom);
1133    }
1134
1135    int32_t displayWidth;
1136    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
1137        ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
1138        mDisplayWidth = displayWidth;
1139    }
1140    int32_t displayHeight;
1141    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
1142        ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
1143        mDisplayHeight = displayHeight;
1144    }
1145
1146    int32_t usableWidth = cropRight - cropLeft + 1;
1147    int32_t usableHeight = cropBottom - cropTop + 1;
1148    if (mDisplayWidth != 0) {
1149        usableWidth = mDisplayWidth;
1150    }
1151    if (mDisplayHeight != 0) {
1152        usableHeight = mDisplayHeight;
1153    }
1154
1155    {
1156        Mutex::Autolock autoLock(mStatsLock);
1157        mStats.mVideoWidth = usableWidth;
1158        mStats.mVideoHeight = usableHeight;
1159    }
1160
1161    int32_t rotationDegrees;
1162    if (!mVideoTrack->getFormat()->findInt32(
1163                kKeyRotation, &rotationDegrees)) {
1164        rotationDegrees = 0;
1165    }
1166
1167    if (rotationDegrees == 90 || rotationDegrees == 270) {
1168        notifyListener_l(
1169                MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
1170    } else {
1171        notifyListener_l(
1172                MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
1173    }
1174}
1175
1176void AwesomePlayer::initRenderer_l() {
1177    ATRACE_CALL();
1178
1179    if (mNativeWindow == NULL) {
1180        return;
1181    }
1182
1183    sp<MetaData> meta = mVideoSource->getFormat();
1184
1185    int32_t format;
1186    const char *component;
1187    int32_t decodedWidth, decodedHeight;
1188    CHECK(meta->findInt32(kKeyColorFormat, &format));
1189    CHECK(meta->findCString(kKeyDecoderComponent, &component));
1190    CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
1191    CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
1192
1193    int32_t rotationDegrees;
1194    if (!mVideoTrack->getFormat()->findInt32(
1195                kKeyRotation, &rotationDegrees)) {
1196        rotationDegrees = 0;
1197    }
1198
1199    mVideoRenderer.clear();
1200
1201    // Must ensure that mVideoRenderer's destructor is actually executed
1202    // before creating a new one.
1203    IPCThreadState::self()->flushCommands();
1204
1205    // Even if set scaling mode fails, we will continue anyway
1206    setVideoScalingMode_l(mVideoScalingMode);
1207    if (USE_SURFACE_ALLOC
1208            && !strncmp(component, "OMX.", 4)
1209            && strncmp(component, "OMX.google.", 11)) {
1210        // Hardware decoders avoid the CPU color conversion by decoding
1211        // directly to ANativeBuffers, so we must use a renderer that
1212        // just pushes those buffers to the ANativeWindow.
1213        mVideoRenderer =
1214            new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
1215    } else {
1216        // Other decoders are instantiated locally and as a consequence
1217        // allocate their buffers in local address space.  This renderer
1218        // then performs a color conversion and copy to get the data
1219        // into the ANativeBuffer.
1220        mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
1221    }
1222}
1223
1224status_t AwesomePlayer::pause() {
1225    ATRACE_CALL();
1226
1227    Mutex::Autolock autoLock(mLock);
1228
1229    modifyFlags(CACHE_UNDERRUN, CLEAR);
1230
1231    return pause_l();
1232}
1233
1234status_t AwesomePlayer::pause_l(bool at_eos) {
1235    if (!(mFlags & PLAYING)) {
1236        if (mAudioTearDown && mAudioTearDownWasPlaying) {
1237            ALOGV("pause_l() during teardown and finishSetDataSource_l() mFlags %x" , mFlags);
1238            mAudioTearDownWasPlaying = false;
1239            notifyListener_l(MEDIA_PAUSED);
1240            mMediaRenderingStartGeneration = ++mStartGeneration;
1241        }
1242        return OK;
1243    }
1244
1245    notifyListener_l(MEDIA_PAUSED);
1246    mMediaRenderingStartGeneration = ++mStartGeneration;
1247
1248    cancelPlayerEvents(true /* keepNotifications */);
1249
1250    if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1251        // If we played the audio stream to completion we
1252        // want to make sure that all samples remaining in the audio
1253        // track's queue are played out.
1254        mAudioPlayer->pause(at_eos /* playPendingSamples */);
1255        // send us a reminder to tear down the AudioPlayer if paused for too long.
1256        if (mOffloadAudio) {
1257            postAudioTearDownEvent(kOffloadPauseMaxUs);
1258        }
1259        modifyFlags(AUDIO_RUNNING, CLEAR);
1260    }
1261
1262    if (mFlags & TEXTPLAYER_INITIALIZED) {
1263        mTextDriver->pause();
1264        modifyFlags(TEXT_RUNNING, CLEAR);
1265    }
1266
1267    modifyFlags(PLAYING, CLEAR);
1268
1269    if (mDecryptHandle != NULL) {
1270        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1271                Playback::PAUSE, 0);
1272    }
1273
1274    uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
1275    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
1276        params |= IMediaPlayerService::kBatteryDataTrackAudio;
1277    }
1278    if (mVideoSource != NULL) {
1279        params |= IMediaPlayerService::kBatteryDataTrackVideo;
1280    }
1281
1282    addBatteryData(params);
1283
1284    return OK;
1285}
1286
1287bool AwesomePlayer::isPlaying() const {
1288    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
1289}
1290
1291status_t AwesomePlayer::setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) {
1292    Mutex::Autolock autoLock(mLock);
1293
1294    status_t err;
1295    if (bufferProducer != NULL) {
1296        err = setNativeWindow_l(new Surface(bufferProducer));
1297    } else {
1298        err = setNativeWindow_l(NULL);
1299    }
1300
1301    return err;
1302}
1303
1304void AwesomePlayer::shutdownVideoDecoder_l() {
1305    if (mVideoBuffer) {
1306        mVideoBuffer->release();
1307        mVideoBuffer = NULL;
1308    }
1309
1310    mVideoSource->stop();
1311
1312    // The following hack is necessary to ensure that the OMX
1313    // component is completely released by the time we may try
1314    // to instantiate it again.
1315    wp<MediaSource> tmp = mVideoSource;
1316    mVideoSource.clear();
1317    while (tmp.promote() != NULL) {
1318        usleep(1000);
1319    }
1320    IPCThreadState::self()->flushCommands();
1321    ALOGV("video decoder shutdown completed");
1322}
1323
1324status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
1325    mNativeWindow = native;
1326
1327    if (mVideoSource == NULL) {
1328        return OK;
1329    }
1330
1331    ALOGV("attempting to reconfigure to use new surface");
1332
1333    bool wasPlaying = (mFlags & PLAYING) != 0;
1334
1335    pause_l();
1336    mVideoRenderer.clear();
1337
1338    shutdownVideoDecoder_l();
1339
1340    status_t err = initVideoDecoder();
1341
1342    if (err != OK) {
1343        ALOGE("failed to reinstantiate video decoder after surface change.");
1344        return err;
1345    }
1346
1347    if (mLastVideoTimeUs >= 0) {
1348        mSeeking = SEEK;
1349        mSeekTimeUs = mLastVideoTimeUs;
1350        modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
1351    }
1352
1353    if (wasPlaying) {
1354        play_l();
1355    }
1356
1357    return OK;
1358}
1359
1360void AwesomePlayer::setAudioSink(
1361        const sp<MediaPlayerBase::AudioSink> &audioSink) {
1362    Mutex::Autolock autoLock(mLock);
1363
1364    mAudioSink = audioSink;
1365}
1366
1367status_t AwesomePlayer::setLooping(bool shouldLoop) {
1368    Mutex::Autolock autoLock(mLock);
1369
1370    modifyFlags(LOOPING, CLEAR);
1371
1372    if (shouldLoop) {
1373        modifyFlags(LOOPING, SET);
1374    }
1375
1376    return OK;
1377}
1378
1379status_t AwesomePlayer::getDuration(int64_t *durationUs) {
1380    Mutex::Autolock autoLock(mMiscStateLock);
1381
1382    if (mDurationUs < 0) {
1383        return UNKNOWN_ERROR;
1384    }
1385
1386    *durationUs = mDurationUs;
1387
1388    return OK;
1389}
1390
1391status_t AwesomePlayer::getPosition(int64_t *positionUs) {
1392    if (mSeeking != NO_SEEK) {
1393        *positionUs = mSeekTimeUs;
1394    } else if (mVideoSource != NULL
1395            && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
1396        Mutex::Autolock autoLock(mMiscStateLock);
1397        *positionUs = mVideoTimeUs;
1398    } else if (mAudioPlayer != NULL) {
1399        *positionUs = mAudioPlayer->getMediaTimeUs();
1400    } else {
1401        *positionUs = 0;
1402    }
1403    return OK;
1404}
1405
1406status_t AwesomePlayer::seekTo(int64_t timeUs) {
1407    ATRACE_CALL();
1408
1409    if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
1410        Mutex::Autolock autoLock(mLock);
1411        return seekTo_l(timeUs);
1412    }
1413
1414    return OK;
1415}
1416
1417status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
1418    if (mFlags & CACHE_UNDERRUN) {
1419        modifyFlags(CACHE_UNDERRUN, CLEAR);
1420        play_l();
1421    }
1422
1423    if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
1424        // Video playback completed before, there's no pending
1425        // video event right now. In order for this new seek
1426        // to be honored, we need to post one.
1427
1428        postVideoEvent_l();
1429    }
1430
1431    mSeeking = SEEK;
1432    mSeekNotificationSent = false;
1433    mSeekTimeUs = timeUs;
1434    modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
1435
1436    if (mFlags & PLAYING) {
1437        notifyListener_l(MEDIA_PAUSED);
1438        mMediaRenderingStartGeneration = ++mStartGeneration;
1439    }
1440
1441    seekAudioIfNecessary_l();
1442
1443    if (mFlags & TEXTPLAYER_INITIALIZED) {
1444        mTextDriver->seekToAsync(mSeekTimeUs);
1445    }
1446
1447    if (!(mFlags & PLAYING)) {
1448        ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
1449             " immediately.");
1450
1451        notifyListener_l(MEDIA_SEEK_COMPLETE);
1452        mSeekNotificationSent = true;
1453
1454        if ((mFlags & PREPARED) && mVideoSource != NULL) {
1455            modifyFlags(SEEK_PREVIEW, SET);
1456            postVideoEvent_l();
1457        }
1458    }
1459
1460    return OK;
1461}
1462
1463void AwesomePlayer::seekAudioIfNecessary_l() {
1464    if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
1465        mAudioPlayer->seekTo(mSeekTimeUs);
1466
1467        mWatchForAudioSeekComplete = true;
1468        mWatchForAudioEOS = true;
1469
1470        if (mDecryptHandle != NULL) {
1471            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1472                    Playback::PAUSE, 0);
1473            mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1474                    Playback::START, mSeekTimeUs / 1000);
1475        }
1476    }
1477}
1478
1479void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1480    CHECK(source != NULL);
1481
1482    mAudioTrack = source;
1483}
1484
1485void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& source) {
1486    CHECK(source != NULL);
1487
1488    if (mTextDriver == NULL) {
1489        mTextDriver = new TimedTextDriver(mListener);
1490    }
1491
1492    mTextDriver->addInBandTextSource(trackIndex, source);
1493}
1494
1495status_t AwesomePlayer::initAudioDecoder() {
1496    ATRACE_CALL();
1497
1498    sp<MetaData> meta = mAudioTrack->getFormat();
1499
1500    const char *mime;
1501    CHECK(meta->findCString(kKeyMIMEType, &mime));
1502    // Check whether there is a hardware codec for this stream
1503    // This doesn't guarantee that the hardware has a free stream
1504    // but it avoids us attempting to open (and re-open) an offload
1505    // stream to hardware that doesn't have the necessary codec
1506    audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
1507    if (mAudioSink != NULL) {
1508        streamType = mAudioSink->getAudioStreamType();
1509    }
1510
1511    mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL),
1512                                     isStreamingHTTP(), streamType);
1513
1514    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
1515        ALOGV("createAudioPlayer: bypass OMX (raw)");
1516        mAudioSource = mAudioTrack;
1517    } else {
1518        // If offloading we still create a OMX decoder as a fall-back
1519        // but we don't start it
1520        mOmxSource = OMXCodec::Create(
1521                mClient.interface(), mAudioTrack->getFormat(),
1522                false, // createEncoder
1523                mAudioTrack);
1524
1525        if (mOffloadAudio) {
1526            ALOGV("createAudioPlayer: bypass OMX (offload)");
1527            mAudioSource = mAudioTrack;
1528        } else {
1529            mAudioSource = mOmxSource;
1530        }
1531    }
1532
1533    if (mAudioSource != NULL) {
1534        int64_t durationUs;
1535        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1536            Mutex::Autolock autoLock(mMiscStateLock);
1537            if (mDurationUs < 0 || durationUs > mDurationUs) {
1538                mDurationUs = durationUs;
1539            }
1540        }
1541
1542        status_t err = mAudioSource->start();
1543
1544        if (err != OK) {
1545            mAudioSource.clear();
1546            mOmxSource.clear();
1547            return err;
1548        }
1549    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1550        // For legacy reasons we're simply going to ignore the absence
1551        // of an audio decoder for QCELP instead of aborting playback
1552        // altogether.
1553        return OK;
1554    }
1555
1556    if (mAudioSource != NULL) {
1557        Mutex::Autolock autoLock(mStatsLock);
1558        TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex);
1559        const char *component;
1560        if (!mAudioSource->getFormat()
1561                ->findCString(kKeyDecoderComponent, &component)) {
1562            component = "none";
1563        }
1564
1565        stat->mDecoderName = component;
1566    }
1567
1568    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1569}
1570
1571void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1572    CHECK(source != NULL);
1573
1574    mVideoTrack = source;
1575}
1576
1577status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
1578    ATRACE_CALL();
1579
1580    // Either the application or the DRM system can independently say
1581    // that there must be a hardware-protected path to an external video sink.
1582    // For now we always require a hardware-protected path to external video sink
1583    // if content is DRMed, but eventually this could be optional per DRM agent.
1584    // When the application wants protection, then
1585    //   (USE_SURFACE_ALLOC && (mSurface != 0) &&
1586    //   (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
1587    // will be true, but that part is already handled by SurfaceFlinger.
1588
1589#ifdef DEBUG_HDCP
1590    // For debugging, we allow a system property to control the protected usage.
1591    // In case of uninitialized or unexpected property, we default to "DRM only".
1592    bool setProtectionBit = false;
1593    char value[PROPERTY_VALUE_MAX];
1594    if (property_get("persist.sys.hdcp_checking", value, NULL)) {
1595        if (!strcmp(value, "never")) {
1596            // nop
1597        } else if (!strcmp(value, "always")) {
1598            setProtectionBit = true;
1599        } else if (!strcmp(value, "drm-only")) {
1600            if (mDecryptHandle != NULL) {
1601                setProtectionBit = true;
1602            }
1603        // property value is empty, or unexpected value
1604        } else {
1605            if (mDecryptHandle != NULL) {
1606                setProtectionBit = true;
1607            }
1608        }
1609    // can' read property value
1610    } else {
1611        if (mDecryptHandle != NULL) {
1612            setProtectionBit = true;
1613        }
1614    }
1615    // note that usage bit is already cleared, so no need to clear it in the "else" case
1616    if (setProtectionBit) {
1617        flags |= OMXCodec::kEnableGrallocUsageProtected;
1618    }
1619#else
1620    if (mDecryptHandle != NULL) {
1621        flags |= OMXCodec::kEnableGrallocUsageProtected;
1622    }
1623#endif
1624    ALOGV("initVideoDecoder flags=0x%x", flags);
1625    mVideoSource = OMXCodec::Create(
1626            mClient.interface(), mVideoTrack->getFormat(),
1627            false, // createEncoder
1628            mVideoTrack,
1629            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
1630
1631    if (mVideoSource != NULL) {
1632        int64_t durationUs;
1633        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1634            Mutex::Autolock autoLock(mMiscStateLock);
1635            if (mDurationUs < 0 || durationUs > mDurationUs) {
1636                mDurationUs = durationUs;
1637            }
1638        }
1639
1640        status_t err = mVideoSource->start();
1641
1642        if (err != OK) {
1643            ALOGE("failed to start video source");
1644            mVideoSource.clear();
1645            return err;
1646        }
1647    }
1648
1649    if (mVideoSource != NULL) {
1650        const char *componentName;
1651        CHECK(mVideoSource->getFormat()
1652                ->findCString(kKeyDecoderComponent, &componentName));
1653
1654        {
1655            Mutex::Autolock autoLock(mStatsLock);
1656            TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex);
1657
1658            stat->mDecoderName = componentName;
1659        }
1660
1661        static const char *kPrefix = "OMX.Nvidia.";
1662        static const char *kSuffix = ".decode";
1663        static const size_t kSuffixLength = strlen(kSuffix);
1664
1665        size_t componentNameLength = strlen(componentName);
1666
1667        if (!strncmp(componentName, kPrefix, strlen(kPrefix))
1668                && componentNameLength >= kSuffixLength
1669                && !strcmp(&componentName[
1670                    componentNameLength - kSuffixLength], kSuffix)) {
1671            modifyFlags(SLOW_DECODER_HACK, SET);
1672        }
1673    }
1674
1675    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1676}
1677
1678void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1679    ATRACE_CALL();
1680
1681    if (mSeeking == SEEK_VIDEO_ONLY) {
1682        mSeeking = NO_SEEK;
1683        return;
1684    }
1685
1686    if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
1687        return;
1688    }
1689
1690    // If we paused, then seeked, then resumed, it is possible that we have
1691    // signaled SEEK_COMPLETE at a copmletely different media time than where
1692    // we are now resuming.  Signal new position to media time provider.
1693    // Cannot signal another SEEK_COMPLETE, as existing clients may not expect
1694    // multiple SEEK_COMPLETE responses to a single seek() request.
1695    if (mSeekNotificationSent && abs(mSeekTimeUs - videoTimeUs) > 10000) {
1696        // notify if we are resuming more than 10ms away from desired seek time
1697        notifyListener_l(MEDIA_SKIPPED);
1698    }
1699
1700    if (mAudioPlayer != NULL) {
1701        ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
1702
1703        // If we don't have a video time, seek audio to the originally
1704        // requested seek time instead.
1705
1706        mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1707        mWatchForAudioSeekComplete = true;
1708        mWatchForAudioEOS = true;
1709    } else if (!mSeekNotificationSent) {
1710        // If we're playing video only, report seek complete now,
1711        // otherwise audio player will notify us later.
1712        notifyListener_l(MEDIA_SEEK_COMPLETE);
1713        mSeekNotificationSent = true;
1714    }
1715
1716    modifyFlags(FIRST_FRAME, SET);
1717    mSeeking = NO_SEEK;
1718
1719    if (mDecryptHandle != NULL) {
1720        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1721                Playback::PAUSE, 0);
1722        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1723                Playback::START, videoTimeUs / 1000);
1724    }
1725}
1726
1727void AwesomePlayer::onVideoEvent() {
1728    ATRACE_CALL();
1729    Mutex::Autolock autoLock(mLock);
1730    if (!mVideoEventPending) {
1731        // The event has been cancelled in reset_l() but had already
1732        // been scheduled for execution at that time.
1733        return;
1734    }
1735    mVideoEventPending = false;
1736
1737    if (mSeeking != NO_SEEK) {
1738        if (mVideoBuffer) {
1739            mVideoBuffer->release();
1740            mVideoBuffer = NULL;
1741        }
1742
1743        if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
1744                && !(mFlags & SEEK_PREVIEW)) {
1745            // We're going to seek the video source first, followed by
1746            // the audio source.
1747            // In order to avoid jumps in the DataSource offset caused by
1748            // the audio codec prefetching data from the old locations
1749            // while the video codec is already reading data from the new
1750            // locations, we'll "pause" the audio source, causing it to
1751            // stop reading input data until a subsequent seek.
1752
1753            if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1754                mAudioPlayer->pause();
1755
1756                modifyFlags(AUDIO_RUNNING, CLEAR);
1757            }
1758            mAudioSource->pause();
1759        }
1760    }
1761
1762    if (!mVideoBuffer) {
1763        MediaSource::ReadOptions options;
1764        if (mSeeking != NO_SEEK) {
1765            ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1766
1767            options.setSeekTo(
1768                    mSeekTimeUs,
1769                    mSeeking == SEEK_VIDEO_ONLY
1770                        ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
1771                        : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1772        }
1773        for (;;) {
1774            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1775            options.clearSeekTo();
1776
1777            if (err != OK) {
1778                CHECK(mVideoBuffer == NULL);
1779
1780                if (err == INFO_FORMAT_CHANGED) {
1781                    ALOGV("VideoSource signalled format change.");
1782
1783                    notifyVideoSize_l();
1784
1785                    if (mVideoRenderer != NULL) {
1786                        mVideoRendererIsPreview = false;
1787                        initRenderer_l();
1788                    }
1789                    continue;
1790                }
1791
1792                // So video playback is complete, but we may still have
1793                // a seek request pending that needs to be applied
1794                // to the audio track.
1795                if (mSeeking != NO_SEEK) {
1796                    ALOGV("video stream ended while seeking!");
1797                }
1798                finishSeekIfNecessary(-1);
1799
1800                if (mAudioPlayer != NULL
1801                        && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1802                    startAudioPlayer_l();
1803                }
1804
1805                modifyFlags(VIDEO_AT_EOS, SET);
1806                postStreamDoneEvent_l(err);
1807                return;
1808            }
1809
1810            if (mVideoBuffer->range_length() == 0) {
1811                // Some decoders, notably the PV AVC software decoder
1812                // return spurious empty buffers that we just want to ignore.
1813
1814                mVideoBuffer->release();
1815                mVideoBuffer = NULL;
1816                continue;
1817            }
1818
1819            break;
1820        }
1821
1822        {
1823            Mutex::Autolock autoLock(mStatsLock);
1824            ++mStats.mNumVideoFramesDecoded;
1825        }
1826    }
1827
1828    int64_t timeUs;
1829    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1830
1831    mLastVideoTimeUs = timeUs;
1832
1833    if (mSeeking == SEEK_VIDEO_ONLY) {
1834        if (mSeekTimeUs > timeUs) {
1835            ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
1836                 mSeekTimeUs, timeUs);
1837        }
1838    }
1839
1840    {
1841        Mutex::Autolock autoLock(mMiscStateLock);
1842        mVideoTimeUs = timeUs;
1843    }
1844
1845    SeekType wasSeeking = mSeeking;
1846    finishSeekIfNecessary(timeUs);
1847
1848    if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1849        status_t err = startAudioPlayer_l();
1850        if (err != OK) {
1851            ALOGE("Starting the audio player failed w/ err %d", err);
1852            return;
1853        }
1854    }
1855
1856    if ((mFlags & TEXTPLAYER_INITIALIZED)
1857            && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
1858        mTextDriver->start();
1859        modifyFlags(TEXT_RUNNING, SET);
1860    }
1861
1862    TimeSource *ts =
1863        ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED))
1864            ? &mSystemTimeSource : mTimeSource;
1865    int64_t systemTimeUs = mSystemTimeSource.getRealTimeUs();
1866
1867    if (mFlags & FIRST_FRAME) {
1868        modifyFlags(FIRST_FRAME, CLEAR);
1869        mSinceLastDropped = 0;
1870        mClockEstimator->reset();
1871        mTimeSourceDeltaUs = estimateRealTimeUs(ts, systemTimeUs) - timeUs;
1872    }
1873
1874    int64_t realTimeUs, mediaTimeUs;
1875    if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1876        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1877        ALOGV("updating TSdelta (%" PRId64 " => %" PRId64 " change %" PRId64 ")",
1878              mTimeSourceDeltaUs, realTimeUs - mediaTimeUs,
1879              mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs));
1880        ATRACE_INT("TS delta change (ms)", (mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)) / 1E3);
1881        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1882    }
1883
1884    if (wasSeeking == SEEK_VIDEO_ONLY) {
1885        int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs;
1886
1887        int64_t latenessUs = nowUs - timeUs;
1888
1889        ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
1890
1891        if (latenessUs > 0) {
1892            ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
1893        }
1894    }
1895
1896    if (wasSeeking == NO_SEEK) {
1897        // Let's display the first frame after seeking right away.
1898
1899        int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs;
1900
1901        int64_t latenessUs = nowUs - timeUs;
1902
1903        ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
1904
1905        if (latenessUs > 500000ll
1906                && mAudioPlayer != NULL
1907                && mAudioPlayer->getMediaTimeMapping(
1908                    &realTimeUs, &mediaTimeUs)) {
1909            if (mWVMExtractor == NULL) {
1910                ALOGI("we're much too late (%.2f secs), video skipping ahead",
1911                     latenessUs / 1E6);
1912
1913                mVideoBuffer->release();
1914                mVideoBuffer = NULL;
1915
1916                mSeeking = SEEK_VIDEO_ONLY;
1917                mSeekTimeUs = mediaTimeUs;
1918
1919                postVideoEvent_l();
1920                return;
1921            } else {
1922                // The widevine extractor doesn't deal well with seeking
1923                // audio and video independently. We'll just have to wait
1924                // until the decoder catches up, which won't be long at all.
1925                ALOGI("we're very late (%.2f secs)", latenessUs / 1E6);
1926            }
1927        }
1928
1929        if (latenessUs > 40000) {
1930            // We're more than 40ms late.
1931            ALOGV("we're late by %lld us (%.2f secs)",
1932                 latenessUs, latenessUs / 1E6);
1933
1934            if (!(mFlags & SLOW_DECODER_HACK)
1935                    || mSinceLastDropped > FRAME_DROP_FREQ)
1936            {
1937                ALOGV("we're late by %lld us (%.2f secs) dropping "
1938                     "one after %d frames",
1939                     latenessUs, latenessUs / 1E6, mSinceLastDropped);
1940
1941                mSinceLastDropped = 0;
1942                mVideoBuffer->release();
1943                mVideoBuffer = NULL;
1944
1945                {
1946                    Mutex::Autolock autoLock(mStatsLock);
1947                    ++mStats.mNumVideoFramesDropped;
1948                }
1949
1950                postVideoEvent_l(0);
1951                return;
1952            }
1953        }
1954
1955        if (latenessUs < -10000) {
1956            // We're more than 10ms early.  Try to schedule at least 12ms
1957            // early (to hit this same check), or just on time.
1958            postVideoEvent_l(latenessUs < -22000 ? 10000 : -latenessUs);
1959            return;
1960        }
1961    }
1962
1963    if ((mNativeWindow != NULL)
1964            && (mVideoRendererIsPreview || mVideoRenderer == NULL)) {
1965        mVideoRendererIsPreview = false;
1966
1967        initRenderer_l();
1968    }
1969
1970    if (mVideoRenderer != NULL) {
1971        mSinceLastDropped++;
1972        mVideoRenderer->render(mVideoBuffer);
1973        if (!mVideoRenderingStarted) {
1974            mVideoRenderingStarted = true;
1975            notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);
1976        }
1977
1978        if (mFlags & PLAYING) {
1979            notifyIfMediaStarted_l();
1980        }
1981    }
1982
1983    mVideoBuffer->release();
1984    mVideoBuffer = NULL;
1985
1986    if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
1987        modifyFlags(SEEK_PREVIEW, CLEAR);
1988        return;
1989    }
1990
1991    /* get next frame time */
1992    if (wasSeeking == NO_SEEK) {
1993        MediaSource::ReadOptions options;
1994        for (;;) {
1995            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1996            if (err != OK) {
1997                // deal with any errors next time
1998                CHECK(mVideoBuffer == NULL);
1999                postVideoEvent_l(0);
2000                return;
2001            }
2002
2003            if (mVideoBuffer->range_length() != 0) {
2004                break;
2005            }
2006
2007            // Some decoders, notably the PV AVC software decoder
2008            // return spurious empty buffers that we just want to ignore.
2009
2010            mVideoBuffer->release();
2011            mVideoBuffer = NULL;
2012        }
2013
2014        {
2015            Mutex::Autolock autoLock(mStatsLock);
2016            ++mStats.mNumVideoFramesDecoded;
2017        }
2018
2019        int64_t nextTimeUs;
2020        CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &nextTimeUs));
2021        systemTimeUs = mSystemTimeSource.getRealTimeUs();
2022        int64_t delayUs = nextTimeUs - estimateRealTimeUs(ts, systemTimeUs) + mTimeSourceDeltaUs;
2023        ATRACE_INT("Frame delta (ms)", (nextTimeUs - timeUs) / 1E3);
2024        ALOGV("next frame in %" PRId64, delayUs);
2025        // try to schedule at least 12ms before due time, or just on time
2026        postVideoEvent_l(delayUs > 22000 ? 10000 : delayUs < 0 ? 0 : delayUs);
2027        return;
2028    }
2029
2030    postVideoEvent_l();
2031}
2032
2033int64_t AwesomePlayer::estimateRealTimeUs(TimeSource *ts, int64_t systemTimeUs) {
2034    if (ts == &mSystemTimeSource) {
2035        return systemTimeUs;
2036    } else {
2037        return (int64_t)mClockEstimator->estimate(systemTimeUs, ts->getRealTimeUs());
2038    }
2039}
2040
2041void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
2042    ATRACE_CALL();
2043
2044    if (mVideoEventPending) {
2045        return;
2046    }
2047
2048    mVideoEventPending = true;
2049    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
2050}
2051
2052void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
2053    if (mStreamDoneEventPending) {
2054        return;
2055    }
2056    mStreamDoneEventPending = true;
2057
2058    mStreamDoneStatus = status;
2059    mQueue.postEvent(mStreamDoneEvent);
2060}
2061
2062void AwesomePlayer::postBufferingEvent_l() {
2063    if (mBufferingEventPending) {
2064        return;
2065    }
2066    mBufferingEventPending = true;
2067    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
2068}
2069
2070void AwesomePlayer::postVideoLagEvent_l() {
2071    if (mVideoLagEventPending) {
2072        return;
2073    }
2074    mVideoLagEventPending = true;
2075    mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
2076}
2077
2078void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) {
2079    Mutex::Autolock autoLock(mAudioLock);
2080    if (mAudioStatusEventPending) {
2081        return;
2082    }
2083    mAudioStatusEventPending = true;
2084    // Do not honor delay when looping in order to limit audio gap
2085    if (mFlags & (LOOPING | AUTO_LOOPING)) {
2086        delayUs = 0;
2087    }
2088    mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
2089}
2090
2091void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) {
2092    Mutex::Autolock autoLock(mAudioLock);
2093    if (mAudioTearDownEventPending) {
2094        return;
2095    }
2096    mAudioTearDownEventPending = true;
2097    mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs);
2098}
2099
2100void AwesomePlayer::onCheckAudioStatus() {
2101    {
2102        Mutex::Autolock autoLock(mAudioLock);
2103        if (!mAudioStatusEventPending) {
2104            // Event was dispatched and while we were blocking on the mutex,
2105            // has already been cancelled.
2106            return;
2107        }
2108
2109        mAudioStatusEventPending = false;
2110    }
2111
2112    Mutex::Autolock autoLock(mLock);
2113
2114    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
2115        mWatchForAudioSeekComplete = false;
2116
2117        if (!mSeekNotificationSent) {
2118            notifyListener_l(MEDIA_SEEK_COMPLETE);
2119            mSeekNotificationSent = true;
2120        }
2121
2122        if (mVideoSource == NULL) {
2123            // For video the mSeeking flag is always reset in finishSeekIfNecessary
2124            mSeeking = NO_SEEK;
2125        }
2126
2127        notifyIfMediaStarted_l();
2128    }
2129
2130    status_t finalStatus;
2131    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
2132        mWatchForAudioEOS = false;
2133        modifyFlags(AUDIO_AT_EOS, SET);
2134        modifyFlags(FIRST_FRAME, SET);
2135        postStreamDoneEvent_l(finalStatus);
2136    }
2137}
2138
2139status_t AwesomePlayer::prepare() {
2140    ATRACE_CALL();
2141    Mutex::Autolock autoLock(mLock);
2142    return prepare_l();
2143}
2144
2145status_t AwesomePlayer::prepare_l() {
2146    if (mFlags & PREPARED) {
2147        return OK;
2148    }
2149
2150    if (mFlags & PREPARING) {
2151        return UNKNOWN_ERROR;
2152    }
2153
2154    mIsAsyncPrepare = false;
2155    status_t err = prepareAsync_l();
2156
2157    if (err != OK) {
2158        return err;
2159    }
2160
2161    while (mFlags & PREPARING) {
2162        mPreparedCondition.wait(mLock);
2163    }
2164
2165    return mPrepareResult;
2166}
2167
2168status_t AwesomePlayer::prepareAsync() {
2169    ATRACE_CALL();
2170    Mutex::Autolock autoLock(mLock);
2171
2172    if (mFlags & PREPARING) {
2173        return UNKNOWN_ERROR;  // async prepare already pending
2174    }
2175
2176    mIsAsyncPrepare = true;
2177    return prepareAsync_l();
2178}
2179
2180status_t AwesomePlayer::prepareAsync_l() {
2181    if (mFlags & PREPARING) {
2182        return UNKNOWN_ERROR;  // async prepare already pending
2183    }
2184
2185    if (!mQueueStarted) {
2186        mQueue.start();
2187        mQueueStarted = true;
2188    }
2189
2190    modifyFlags(PREPARING, SET);
2191    mAsyncPrepareEvent = new AwesomeEvent(
2192            this, &AwesomePlayer::onPrepareAsyncEvent);
2193
2194    mQueue.postEvent(mAsyncPrepareEvent);
2195
2196    return OK;
2197}
2198
2199status_t AwesomePlayer::finishSetDataSource_l() {
2200    ATRACE_CALL();
2201    sp<DataSource> dataSource;
2202
2203    bool isWidevineStreaming = false;
2204    if (!strncasecmp("widevine://", mUri.string(), 11)) {
2205        isWidevineStreaming = true;
2206
2207        String8 newURI = String8("http://");
2208        newURI.append(mUri.string() + 11);
2209
2210        mUri = newURI;
2211    }
2212
2213    AString sniffedMIME;
2214
2215    if (!strncasecmp("http://", mUri.string(), 7)
2216            || !strncasecmp("https://", mUri.string(), 8)
2217            || isWidevineStreaming) {
2218        mConnectingDataSource = HTTPBase::Create(
2219                (mFlags & INCOGNITO)
2220                    ? HTTPBase::kFlagIncognito
2221                    : 0);
2222
2223        if (mUIDValid) {
2224            mConnectingDataSource->setUID(mUID);
2225        }
2226
2227        String8 cacheConfig;
2228        bool disconnectAtHighwatermark;
2229        NuCachedSource2::RemoveCacheSpecificHeaders(
2230                &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark);
2231
2232        mLock.unlock();
2233        status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
2234        mLock.lock();
2235
2236        if (err != OK) {
2237            mConnectingDataSource.clear();
2238
2239            ALOGI("mConnectingDataSource->connect() returned %d", err);
2240            return err;
2241        }
2242
2243        if (!isWidevineStreaming) {
2244            // The widevine extractor does its own caching.
2245
2246#if 0
2247            mCachedSource = new NuCachedSource2(
2248                    new ThrottledSource(
2249                        mConnectingDataSource, 50 * 1024 /* bytes/sec */));
2250#else
2251            mCachedSource = new NuCachedSource2(
2252                    mConnectingDataSource,
2253                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
2254                    disconnectAtHighwatermark);
2255#endif
2256
2257            dataSource = mCachedSource;
2258        } else {
2259            dataSource = mConnectingDataSource;
2260        }
2261
2262        mConnectingDataSource.clear();
2263
2264        String8 contentType = dataSource->getMIMEType();
2265
2266        if (strncasecmp(contentType.string(), "audio/", 6)) {
2267            // We're not doing this for streams that appear to be audio-only
2268            // streams to ensure that even low bandwidth streams start
2269            // playing back fairly instantly.
2270
2271            // We're going to prefill the cache before trying to instantiate
2272            // the extractor below, as the latter is an operation that otherwise
2273            // could block on the datasource for a significant amount of time.
2274            // During that time we'd be unable to abort the preparation phase
2275            // without this prefill.
2276            if (mCachedSource != NULL) {
2277                // We're going to prefill the cache before trying to instantiate
2278                // the extractor below, as the latter is an operation that otherwise
2279                // could block on the datasource for a significant amount of time.
2280                // During that time we'd be unable to abort the preparation phase
2281                // without this prefill.
2282
2283                mLock.unlock();
2284
2285                // Initially make sure we have at least 192 KB for the sniff
2286                // to complete without blocking.
2287                static const size_t kMinBytesForSniffing = 192 * 1024;
2288
2289                off64_t metaDataSize = -1ll;
2290                for (;;) {
2291                    status_t finalStatus;
2292                    size_t cachedDataRemaining =
2293                        mCachedSource->approxDataRemaining(&finalStatus);
2294
2295                    if (finalStatus != OK
2296                            || (metaDataSize >= 0
2297                                && cachedDataRemaining >= metaDataSize)
2298                            || (mFlags & PREPARE_CANCELLED)) {
2299                        break;
2300                    }
2301
2302                    ALOGV("now cached %d bytes of data", cachedDataRemaining);
2303
2304                    if (metaDataSize < 0
2305                            && cachedDataRemaining >= kMinBytesForSniffing) {
2306                        String8 tmp;
2307                        float confidence;
2308                        sp<AMessage> meta;
2309                        if (!dataSource->sniff(&tmp, &confidence, &meta)) {
2310                            mLock.lock();
2311                            return UNKNOWN_ERROR;
2312                        }
2313
2314                        // We successfully identified the file's extractor to
2315                        // be, remember this mime type so we don't have to
2316                        // sniff it again when we call MediaExtractor::Create()
2317                        // below.
2318                        sniffedMIME = tmp.string();
2319
2320                        if (meta == NULL
2321                                || !meta->findInt64("meta-data-size",
2322                                     reinterpret_cast<int64_t*>(&metaDataSize))) {
2323                            metaDataSize = kHighWaterMarkBytes;
2324                        }
2325
2326                        CHECK_GE(metaDataSize, 0ll);
2327                        ALOGV("metaDataSize = %lld bytes", metaDataSize);
2328                    }
2329
2330                    usleep(200000);
2331                }
2332
2333                mLock.lock();
2334            }
2335
2336            if (mFlags & PREPARE_CANCELLED) {
2337                ALOGI("Prepare cancelled while waiting for initial cache fill.");
2338                return UNKNOWN_ERROR;
2339            }
2340        }
2341    } else {
2342        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
2343    }
2344
2345    if (dataSource == NULL) {
2346        return UNKNOWN_ERROR;
2347    }
2348
2349    sp<MediaExtractor> extractor;
2350
2351    if (isWidevineStreaming) {
2352        String8 mimeType;
2353        float confidence;
2354        sp<AMessage> dummy;
2355        bool success;
2356
2357        // SniffWVM is potentially blocking since it may require network access.
2358        // Do not call it with mLock held.
2359        mLock.unlock();
2360        success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
2361        mLock.lock();
2362
2363        if (!success
2364                || strcasecmp(
2365                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
2366            return ERROR_UNSUPPORTED;
2367        }
2368
2369        mWVMExtractor = new WVMExtractor(dataSource);
2370        mWVMExtractor->setAdaptiveStreamingMode(true);
2371        if (mUIDValid)
2372            mWVMExtractor->setUID(mUID);
2373        extractor = mWVMExtractor;
2374    } else {
2375        extractor = MediaExtractor::Create(
2376                dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
2377
2378        if (extractor == NULL) {
2379            return UNKNOWN_ERROR;
2380        }
2381    }
2382
2383    if (extractor->getDrmFlag()) {
2384        checkDrmStatus(dataSource);
2385    }
2386
2387    status_t err = setDataSource_l(extractor);
2388
2389    if (err != OK) {
2390        mWVMExtractor.clear();
2391
2392        return err;
2393    }
2394
2395    return OK;
2396}
2397
2398void AwesomePlayer::abortPrepare(status_t err) {
2399    CHECK(err != OK);
2400
2401    if (mIsAsyncPrepare) {
2402        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
2403    }
2404
2405    mPrepareResult = err;
2406    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
2407    mAsyncPrepareEvent = NULL;
2408    mPreparedCondition.broadcast();
2409    mAudioTearDown = false;
2410}
2411
2412// static
2413bool AwesomePlayer::ContinuePreparation(void *cookie) {
2414    AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
2415
2416    return (me->mFlags & PREPARE_CANCELLED) == 0;
2417}
2418
2419void AwesomePlayer::onPrepareAsyncEvent() {
2420    Mutex::Autolock autoLock(mLock);
2421    beginPrepareAsync_l();
2422}
2423
2424void AwesomePlayer::beginPrepareAsync_l() {
2425    if (mFlags & PREPARE_CANCELLED) {
2426        ALOGI("prepare was cancelled before doing anything");
2427        abortPrepare(UNKNOWN_ERROR);
2428        return;
2429    }
2430
2431    if (mUri.size() > 0) {
2432        status_t err = finishSetDataSource_l();
2433
2434        if (err != OK) {
2435            abortPrepare(err);
2436            return;
2437        }
2438    }
2439
2440    if (mVideoTrack != NULL && mVideoSource == NULL) {
2441        status_t err = initVideoDecoder();
2442
2443        if (err != OK) {
2444            abortPrepare(err);
2445            return;
2446        }
2447    }
2448
2449    if (mAudioTrack != NULL && mAudioSource == NULL) {
2450        status_t err = initAudioDecoder();
2451
2452        if (err != OK) {
2453            abortPrepare(err);
2454            return;
2455        }
2456    }
2457
2458    modifyFlags(PREPARING_CONNECTED, SET);
2459
2460    if (isStreamingHTTP()) {
2461        postBufferingEvent_l();
2462    } else {
2463        finishAsyncPrepare_l();
2464    }
2465}
2466
2467void AwesomePlayer::finishAsyncPrepare_l() {
2468    if (mIsAsyncPrepare) {
2469        if (mVideoSource == NULL) {
2470            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
2471        } else {
2472            notifyVideoSize_l();
2473        }
2474
2475        notifyListener_l(MEDIA_PREPARED);
2476    }
2477
2478    mPrepareResult = OK;
2479    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
2480    modifyFlags(PREPARED, SET);
2481    mAsyncPrepareEvent = NULL;
2482    mPreparedCondition.broadcast();
2483
2484    if (mAudioTearDown) {
2485        if (mPrepareResult == OK) {
2486            if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
2487                seekTo_l(mAudioTearDownPosition);
2488            }
2489
2490            if (mAudioTearDownWasPlaying) {
2491                modifyFlags(CACHE_UNDERRUN, CLEAR);
2492                play_l();
2493            }
2494        }
2495        mAudioTearDown = false;
2496    }
2497}
2498
2499uint32_t AwesomePlayer::flags() const {
2500    return mExtractorFlags;
2501}
2502
2503void AwesomePlayer::postAudioEOS(int64_t delayUs) {
2504    postCheckAudioStatusEvent(delayUs);
2505}
2506
2507void AwesomePlayer::postAudioSeekComplete() {
2508    postCheckAudioStatusEvent(0);
2509}
2510
2511void AwesomePlayer::postAudioTearDown() {
2512    postAudioTearDownEvent(0);
2513}
2514
2515status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
2516    switch (key) {
2517        case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
2518        {
2519            return setCacheStatCollectFreq(request);
2520        }
2521        case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE:
2522        {
2523            if (mAudioPlayer != NULL) {
2524                return mAudioPlayer->setPlaybackRatePermille(request.readInt32());
2525            } else {
2526                return NO_INIT;
2527            }
2528        }
2529        default:
2530        {
2531            return ERROR_UNSUPPORTED;
2532        }
2533    }
2534}
2535
2536status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) {
2537    if (mCachedSource != NULL) {
2538        int32_t freqMs = request.readInt32();
2539        ALOGD("Request to keep cache stats in the past %d ms",
2540            freqMs);
2541        return mCachedSource->setCacheStatCollectFreq(freqMs);
2542    }
2543    return ERROR_UNSUPPORTED;
2544}
2545
2546status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
2547    switch (key) {
2548    case KEY_PARAMETER_AUDIO_CHANNEL_COUNT:
2549        {
2550            int32_t channelCount;
2551            if (mAudioTrack == 0 ||
2552                    !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) {
2553                channelCount = 0;
2554            }
2555            reply->writeInt32(channelCount);
2556        }
2557        return OK;
2558    default:
2559        {
2560            return ERROR_UNSUPPORTED;
2561        }
2562    }
2563}
2564
2565status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
2566    Mutex::Autolock autoLock(mLock);
2567    size_t trackCount = mExtractor->countTracks();
2568    if (mTextDriver != NULL) {
2569        trackCount += mTextDriver->countExternalTracks();
2570    }
2571
2572    reply->writeInt32(trackCount);
2573    for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
2574        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
2575
2576        const char *_mime;
2577        CHECK(meta->findCString(kKeyMIMEType, &_mime));
2578
2579        String8 mime = String8(_mime);
2580
2581        reply->writeInt32(2); // 2 fields
2582
2583        if (!strncasecmp(mime.string(), "video/", 6)) {
2584            reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
2585        } else if (!strncasecmp(mime.string(), "audio/", 6)) {
2586            reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
2587        } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
2588            reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
2589        } else {
2590            reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
2591        }
2592
2593        const char *lang;
2594        if (!meta->findCString(kKeyMediaLanguage, &lang)) {
2595            lang = "und";
2596        }
2597        reply->writeString16(String16(lang));
2598    }
2599
2600    if (mTextDriver != NULL) {
2601        mTextDriver->getExternalTrackInfo(reply);
2602    }
2603    return OK;
2604}
2605
2606status_t AwesomePlayer::selectAudioTrack_l(
2607        const sp<MediaSource>& source, size_t trackIndex) {
2608
2609    ALOGI("selectAudioTrack_l: trackIndex=%zu, mFlags=0x%x", trackIndex, mFlags);
2610
2611    {
2612        Mutex::Autolock autoLock(mStatsLock);
2613        if ((ssize_t)trackIndex == mActiveAudioTrackIndex) {
2614            ALOGI("Track %zu is active. Does nothing.", trackIndex);
2615            return OK;
2616        }
2617        //mStats.mFlags = mFlags;
2618    }
2619
2620    if (mSeeking != NO_SEEK) {
2621        ALOGE("Selecting a track while seeking is not supported");
2622        return ERROR_UNSUPPORTED;
2623    }
2624
2625    if ((mFlags & PREPARED) == 0) {
2626        ALOGE("Data source has not finished preparation");
2627        return ERROR_UNSUPPORTED;
2628    }
2629
2630    CHECK(source != NULL);
2631    bool wasPlaying = (mFlags & PLAYING) != 0;
2632
2633    pause_l();
2634
2635    int64_t curTimeUs;
2636    CHECK_EQ(getPosition(&curTimeUs), (status_t)OK);
2637
2638    if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
2639            && mAudioSource != NULL) {
2640        // If we had an audio player, it would have effectively
2641        // taken possession of the audio source and stopped it when
2642        // _it_ is stopped. Otherwise this is still our responsibility.
2643        mAudioSource->stop();
2644    }
2645    mAudioSource.clear();
2646    mOmxSource.clear();
2647
2648    mTimeSource = NULL;
2649
2650    delete mAudioPlayer;
2651    mAudioPlayer = NULL;
2652
2653    modifyFlags(AUDIOPLAYER_STARTED, CLEAR);
2654
2655    setAudioSource(source);
2656
2657    modifyFlags(AUDIO_AT_EOS, CLEAR);
2658    modifyFlags(AT_EOS, CLEAR);
2659
2660    status_t err;
2661    if ((err = initAudioDecoder()) != OK) {
2662        ALOGE("Failed to init audio decoder: 0x%x", err);
2663        return err;
2664    }
2665
2666    mSeekNotificationSent = true;
2667    seekTo_l(curTimeUs);
2668
2669    if (wasPlaying) {
2670        play_l();
2671    }
2672
2673    mActiveAudioTrackIndex = trackIndex;
2674
2675    return OK;
2676}
2677
2678status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) {
2679    ATRACE_CALL();
2680    ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select);
2681    Mutex::Autolock autoLock(mLock);
2682    size_t trackCount = mExtractor->countTracks();
2683    if (mTextDriver != NULL) {
2684        trackCount += mTextDriver->countExternalTracks();
2685    }
2686    if (trackIndex >= trackCount) {
2687        ALOGE("Track index (%zu) is out of range [0, %zu)", trackIndex, trackCount);
2688        return ERROR_OUT_OF_RANGE;
2689    }
2690
2691    bool isAudioTrack = false;
2692    if (trackIndex < mExtractor->countTracks()) {
2693        sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex);
2694        const char *mime;
2695        CHECK(meta->findCString(kKeyMIMEType, &mime));
2696        isAudioTrack = !strncasecmp(mime, "audio/", 6);
2697
2698        if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) {
2699            ALOGE("Track %zu is not either audio or timed text", trackIndex);
2700            return ERROR_UNSUPPORTED;
2701        }
2702    }
2703
2704    if (isAudioTrack) {
2705        if (!select) {
2706            ALOGE("Deselect an audio track (%zu) is not supported", trackIndex);
2707            return ERROR_UNSUPPORTED;
2708        }
2709        return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex);
2710    }
2711
2712    // Timed text track handling
2713    if (mTextDriver == NULL) {
2714        return INVALID_OPERATION;
2715    }
2716
2717    status_t err = OK;
2718    if (select) {
2719        err = mTextDriver->selectTrack(trackIndex);
2720        if (err == OK) {
2721            modifyFlags(TEXTPLAYER_INITIALIZED, SET);
2722            if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
2723                mTextDriver->start();
2724                modifyFlags(TEXT_RUNNING, SET);
2725            }
2726        }
2727    } else {
2728        err = mTextDriver->unselectTrack(trackIndex);
2729        if (err == OK) {
2730            modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
2731            modifyFlags(TEXT_RUNNING, CLEAR);
2732        }
2733    }
2734    return err;
2735}
2736
2737size_t AwesomePlayer::countTracks() const {
2738    return mExtractor->countTracks() + mTextDriver->countExternalTracks();
2739}
2740
2741status_t AwesomePlayer::setVideoScalingMode(int32_t mode) {
2742    Mutex::Autolock lock(mLock);
2743    return setVideoScalingMode_l(mode);
2744}
2745
2746status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) {
2747    mVideoScalingMode = mode;
2748    if (mNativeWindow != NULL) {
2749        status_t err = native_window_set_scaling_mode(
2750                mNativeWindow.get(), mVideoScalingMode);
2751        if (err != OK) {
2752            ALOGW("Failed to set scaling mode: %d", err);
2753        }
2754        return err;
2755    }
2756    return OK;
2757}
2758
2759status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) {
2760    ATRACE_CALL();
2761    if (NULL == reply) {
2762        return android::BAD_VALUE;
2763    }
2764    int32_t methodId;
2765    status_t ret = request.readInt32(&methodId);
2766    if (ret != android::OK) {
2767        return ret;
2768    }
2769    switch(methodId) {
2770        case INVOKE_ID_SET_VIDEO_SCALING_MODE:
2771        {
2772            int mode = request.readInt32();
2773            return setVideoScalingMode(mode);
2774        }
2775
2776        case INVOKE_ID_GET_TRACK_INFO:
2777        {
2778            return getTrackInfo(reply);
2779        }
2780        case INVOKE_ID_ADD_EXTERNAL_SOURCE:
2781        {
2782            Mutex::Autolock autoLock(mLock);
2783            if (mTextDriver == NULL) {
2784                mTextDriver = new TimedTextDriver(mListener);
2785            }
2786            // String values written in Parcel are UTF-16 values.
2787            String8 uri(request.readString16());
2788            String8 mimeType(request.readString16());
2789            size_t nTracks = countTracks();
2790            return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType);
2791        }
2792        case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
2793        {
2794            Mutex::Autolock autoLock(mLock);
2795            if (mTextDriver == NULL) {
2796                mTextDriver = new TimedTextDriver(mListener);
2797            }
2798            int fd         = request.readFileDescriptor();
2799            off64_t offset = request.readInt64();
2800            off64_t length  = request.readInt64();
2801            String8 mimeType(request.readString16());
2802            size_t nTracks = countTracks();
2803            return mTextDriver->addOutOfBandTextSource(
2804                    nTracks, fd, offset, length, mimeType);
2805        }
2806        case INVOKE_ID_SELECT_TRACK:
2807        {
2808            int trackIndex = request.readInt32();
2809            return selectTrack(trackIndex, true /* select */);
2810        }
2811        case INVOKE_ID_UNSELECT_TRACK:
2812        {
2813            int trackIndex = request.readInt32();
2814            return selectTrack(trackIndex, false /* select */);
2815        }
2816        default:
2817        {
2818            return ERROR_UNSUPPORTED;
2819        }
2820    }
2821    // It will not reach here.
2822    return OK;
2823}
2824
2825bool AwesomePlayer::isStreamingHTTP() const {
2826    return mCachedSource != NULL || mWVMExtractor != NULL;
2827}
2828
2829status_t AwesomePlayer::dump(
2830        int fd, const Vector<String16> & /* args */) const {
2831    Mutex::Autolock autoLock(mStatsLock);
2832
2833    FILE *out = fdopen(dup(fd), "w");
2834
2835    fprintf(out, " AwesomePlayer\n");
2836    if (mStats.mFd < 0) {
2837        fprintf(out, "  URI(suppressed)");
2838    } else {
2839        fprintf(out, "  fd(%d)", mStats.mFd);
2840    }
2841
2842    fprintf(out, ", flags(0x%08x)", mStats.mFlags);
2843
2844    if (mStats.mBitrate >= 0) {
2845        fprintf(out, ", bitrate(%" PRId64 " bps)", mStats.mBitrate);
2846    }
2847
2848    fprintf(out, "\n");
2849
2850    for (size_t i = 0; i < mStats.mTracks.size(); ++i) {
2851        const TrackStat &stat = mStats.mTracks.itemAt(i);
2852
2853        fprintf(out, "  Track %zu\n", i + 1);
2854        fprintf(out, "   MIME(%s)", stat.mMIME.string());
2855
2856        if (!stat.mDecoderName.isEmpty()) {
2857            fprintf(out, ", decoder(%s)", stat.mDecoderName.string());
2858        }
2859
2860        fprintf(out, "\n");
2861
2862        if ((ssize_t)i == mStats.mVideoTrackIndex) {
2863            fprintf(out,
2864                    "   videoDimensions(%d x %d), "
2865                    "numVideoFramesDecoded(%" PRId64 "), "
2866                    "numVideoFramesDropped(%" PRId64 ")\n",
2867                    mStats.mVideoWidth,
2868                    mStats.mVideoHeight,
2869                    mStats.mNumVideoFramesDecoded,
2870                    mStats.mNumVideoFramesDropped);
2871        }
2872    }
2873
2874    fclose(out);
2875    out = NULL;
2876
2877    return OK;
2878}
2879
2880void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) {
2881    switch (mode) {
2882        case SET:
2883            mFlags |= value;
2884            break;
2885        case CLEAR:
2886            if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) {
2887                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
2888            }
2889            mFlags &= ~value;
2890            break;
2891        case ASSIGN:
2892            mFlags = value;
2893            break;
2894        default:
2895            TRESPASS();
2896    }
2897
2898    {
2899        Mutex::Autolock autoLock(mStatsLock);
2900        mStats.mFlags = mFlags;
2901    }
2902}
2903
2904void AwesomePlayer::onAudioTearDownEvent() {
2905
2906    Mutex::Autolock autoLock(mLock);
2907    if (!mAudioTearDownEventPending) {
2908        return;
2909    }
2910    mAudioTearDownEventPending = false;
2911
2912    ALOGV("onAudioTearDownEvent");
2913
2914    // stream info is cleared by reset_l() so copy what we need
2915    mAudioTearDownWasPlaying = (mFlags & PLAYING);
2916    KeyedVector<String8, String8> uriHeaders(mUriHeaders);
2917    sp<DataSource> fileSource(mFileSource);
2918
2919    mStatsLock.lock();
2920    String8 uri(mStats.mURI);
2921    mStatsLock.unlock();
2922
2923    // get current position so we can start recreated stream from here
2924    getPosition(&mAudioTearDownPosition);
2925
2926    // Reset and recreate
2927    reset_l();
2928
2929    status_t err;
2930
2931    if (fileSource != NULL) {
2932        mFileSource = fileSource;
2933        err = setDataSource_l(fileSource);
2934    } else {
2935        err = setDataSource_l(uri, &uriHeaders);
2936    }
2937
2938    mFlags |= PREPARING;
2939    if ( err != OK ) {
2940        // This will force beingPrepareAsync_l() to notify
2941        // a MEDIA_ERROR to the client and abort the prepare
2942        mFlags |= PREPARE_CANCELLED;
2943    }
2944
2945    mAudioTearDown = true;
2946    mIsAsyncPrepare = true;
2947
2948    // Call prepare for the host decoding
2949    beginPrepareAsync_l();
2950}
2951
2952}  // namespace android
2953