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