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