blob: f084e283a8e80302daa4e454bdf03e3a2bca784a [file] [log] [blame]
Andreas Huber27366fc2009-11-20 09:32:46 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "AwesomePlayer"
19#include <utils/Log.h>
20
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080021#include <dlfcn.h>
22
Andreas Huber7a747b82010-06-07 15:19:40 -070023#include "include/ARTSPController.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080024#include "include/AwesomePlayer.h"
Andreas Huber7a747b82010-06-07 15:19:40 -070025#include "include/LiveSource.h"
Andreas Huber1314e732009-12-14 14:18:22 -080026#include "include/SoftwareRenderer.h"
Andreas Huber4d61f602010-06-10 11:17:50 -070027#include "include/NuCachedSource2.h"
28#include "include/ThrottledSource.h"
Andreas Huber54d09722010-10-12 11:34:37 -070029#include "include/MPEG2TSExtractor.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080030
Andreas Huber57648e42010-08-04 10:14:30 -070031#include "ARTPSession.h"
32#include "APacketSource.h"
33#include "ASessionDescription.h"
34#include "UDPPusher.h"
35
Andreas Hubera67d5382009-12-10 15:32:12 -080036#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080037#include <media/stagefright/AudioPlayer.h>
38#include <media/stagefright/DataSource.h>
39#include <media/stagefright/FileSource.h>
40#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080041#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080042#include <media/stagefright/MediaExtractor.h>
43#include <media/stagefright/MediaDebug.h>
44#include <media/stagefright/MediaSource.h>
45#include <media/stagefright/MetaData.h>
46#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080047
Andreas Hubere3c01832010-08-16 08:49:37 -070048#include <surfaceflinger/Surface.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080049
Andreas Huber7a747b82010-06-07 15:19:40 -070050#include <media/stagefright/foundation/ALooper.h>
Andreas Huber202348e2010-06-07 14:35:29 -070051
Andreas Huber27366fc2009-11-20 09:32:46 -080052namespace android {
53
Andreas Huber87ab9cd2010-09-03 13:20:33 -070054static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
55static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
56
Andreas Huber27366fc2009-11-20 09:32:46 -080057struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080058 AwesomeEvent(
59 AwesomePlayer *player,
60 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080061 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080062 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080063 }
64
65protected:
66 virtual ~AwesomeEvent() {}
67
68 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080069 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080070 }
71
72private:
73 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080074 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080075
76 AwesomeEvent(const AwesomeEvent &);
77 AwesomeEvent &operator=(const AwesomeEvent &);
78};
79
Andreas Huber1314e732009-12-14 14:18:22 -080080struct AwesomeRemoteRenderer : public AwesomeRenderer {
81 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
82 : mTarget(target) {
83 }
84
85 virtual void render(MediaBuffer *buffer) {
86 void *id;
87 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
88 mTarget->render((IOMX::buffer_id)id);
89 }
90 }
91
92private:
93 sp<IOMXRenderer> mTarget;
94
95 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
96 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
97};
98
99struct AwesomeLocalRenderer : public AwesomeRenderer {
100 AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800101 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800102 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -0800103 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700104 const sp<ISurface> &isurface,
105 const sp<Surface> &surface,
Andreas Huber1314e732009-12-14 14:18:22 -0800106 size_t displayWidth, size_t displayHeight,
107 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800108 : mTarget(NULL),
109 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800110 init(previewOnly, componentName,
Andreas Hubere3c01832010-08-16 08:49:37 -0700111 colorFormat, isurface, surface, displayWidth,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800112 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800113 }
114
115 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800116 render((const uint8_t *)buffer->data() + buffer->range_offset(),
117 buffer->range_length());
118 }
119
120 void render(const void *data, size_t size) {
121 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800122 }
123
124protected:
125 virtual ~AwesomeLocalRenderer() {
126 delete mTarget;
127 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800128
129 if (mLibHandle) {
130 dlclose(mLibHandle);
131 mLibHandle = NULL;
132 }
Andreas Huber1314e732009-12-14 14:18:22 -0800133 }
134
135private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800136 VideoRenderer *mTarget;
137 void *mLibHandle;
138
139 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800140 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800141 const char *componentName,
142 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700143 const sp<ISurface> &isurface,
144 const sp<Surface> &surface,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800145 size_t displayWidth, size_t displayHeight,
146 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800147
148 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
149 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
150};
151
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800152void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800153 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800154 const char *componentName,
155 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700156 const sp<ISurface> &isurface,
157 const sp<Surface> &surface,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800158 size_t displayWidth, size_t displayHeight,
159 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800160 if (!previewOnly) {
161 // We will stick to the vanilla software-color-converting renderer
162 // for "previewOnly" mode, to avoid unneccessarily switching overlays
163 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800164
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800165 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800166
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800167 if (mLibHandle) {
168 typedef VideoRenderer *(*CreateRendererFunc)(
169 const sp<ISurface> &surface,
170 const char *componentName,
171 OMX_COLOR_FORMATTYPE colorFormat,
172 size_t displayWidth, size_t displayHeight,
173 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800174
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800175 CreateRendererFunc func =
176 (CreateRendererFunc)dlsym(
177 mLibHandle,
178 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
179 "OMX_COLOR_FORMATTYPEjjjj");
180
181 if (func) {
182 mTarget =
Andreas Hubere3c01832010-08-16 08:49:37 -0700183 (*func)(isurface, componentName, colorFormat,
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800184 displayWidth, displayHeight,
185 decodedWidth, decodedHeight);
186 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800187 }
188 }
189
190 if (mTarget == NULL) {
191 mTarget = new SoftwareRenderer(
192 colorFormat, surface, displayWidth, displayHeight,
193 decodedWidth, decodedHeight);
194 }
195}
196
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700197struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
198 AwesomeNativeWindowRenderer(const sp<ANativeWindow> &nativeWindow)
199 : mNativeWindow(nativeWindow) {
200 }
201
202 virtual void render(MediaBuffer *buffer) {
203 status_t err = mNativeWindow->queueBuffer(
204 mNativeWindow.get(), buffer->graphicBuffer().get());
205 if (err != 0) {
206 LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
207 -err);
208 return;
209 }
210
211 sp<MetaData> metaData = buffer->meta_data();
212 metaData->setInt32(kKeyRendered, 1);
213 }
214
215protected:
216 virtual ~AwesomeNativeWindowRenderer() {}
217
218private:
219 sp<ANativeWindow> mNativeWindow;
220
221 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
222 AwesomeNativeWindowRenderer &operator=(
223 const AwesomeNativeWindowRenderer &);
224};
225
Andreas Huber27366fc2009-11-20 09:32:46 -0800226AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800227 : mQueueStarted(false),
228 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800229 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800230 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800231 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700232 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800233 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800234 mVideoBuffer(NULL),
Gloria Wangd5770912010-06-22 13:55:38 -0700235 mSuspensionState(NULL),
236 mDecryptHandle(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800237 CHECK_EQ(mClient.connect(), OK);
238
239 DataSource::RegisterDefaultSniffers();
240
Andreas Huber6be780e2010-02-08 14:40:30 -0800241 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800242 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800243 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800244 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800245 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800246 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800247
248 mCheckAudioStatusEvent = new AwesomeEvent(
249 this, &AwesomePlayer::onCheckAudioStatus);
250
Andreas Huber70d10c02010-02-03 11:37:29 -0800251 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800252
Andreas Huber27366fc2009-11-20 09:32:46 -0800253 reset();
254}
255
256AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800257 if (mQueueStarted) {
258 mQueue.stop();
259 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800260
261 reset();
262
263 mClient.disconnect();
264}
265
Andreas Huberb9e63832010-01-26 16:20:10 -0800266void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800267 mQueue.cancelEvent(mVideoEvent->eventID());
268 mVideoEventPending = false;
269 mQueue.cancelEvent(mStreamDoneEvent->eventID());
270 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800271 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
272 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800273
274 if (!keepBufferingGoing) {
275 mQueue.cancelEvent(mBufferingEvent->eventID());
276 mBufferingEventPending = false;
277 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800278}
279
Andreas Hubera3f43842010-01-21 10:28:45 -0800280void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800281 Mutex::Autolock autoLock(mLock);
282 mListener = listener;
283}
284
Andreas Huber433c9ac2010-01-27 16:49:05 -0800285status_t AwesomePlayer::setDataSource(
286 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800287 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800288 return setDataSource_l(uri, headers);
289}
Andreas Huber27366fc2009-11-20 09:32:46 -0800290
Andreas Huberba7ec912010-02-12 10:42:02 -0800291status_t AwesomePlayer::setDataSource_l(
292 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800293 reset_l();
294
Andreas Huberffdf4782010-02-09 14:05:43 -0800295 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800296
Andreas Huberffdf4782010-02-09 14:05:43 -0800297 if (headers) {
298 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800299 }
300
Andreas Huberffdf4782010-02-09 14:05:43 -0800301 // The actual work will be done during preparation in the call to
302 // ::finishSetDataSource_l to avoid blocking the calling thread in
303 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800304
Andreas Huberffdf4782010-02-09 14:05:43 -0800305 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800306}
307
308status_t AwesomePlayer::setDataSource(
309 int fd, int64_t offset, int64_t length) {
310 Mutex::Autolock autoLock(mLock);
311
312 reset_l();
313
Andreas Huberba7ec912010-02-12 10:42:02 -0800314 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800315
Andreas Huberba7ec912010-02-12 10:42:02 -0800316 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800317
318 if (err != OK) {
319 return err;
320 }
321
Andreas Huberba7ec912010-02-12 10:42:02 -0800322 mFileSource = dataSource;
323
324 return setDataSource_l(dataSource);
325}
326
327status_t AwesomePlayer::setDataSource_l(
328 const sp<DataSource> &dataSource) {
329 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800330
331 if (extractor == NULL) {
332 return UNKNOWN_ERROR;
333 }
334
Gloria Wangd5770912010-06-22 13:55:38 -0700335 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangeab18ea2010-10-29 10:09:47 -0700336 if (mDecryptHandle != NULL
337 && RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
338 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
Gloria Wangd5770912010-06-22 13:55:38 -0700339 }
340
Andreas Huber27366fc2009-11-20 09:32:46 -0800341 return setDataSource_l(extractor);
342}
343
344status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700345 // Attempt to approximate overall stream bitrate by summing all
346 // tracks' individual bitrates, if not all of them advertise bitrate,
347 // we have to fail.
348
349 int64_t totalBitRate = 0;
350
351 for (size_t i = 0; i < extractor->countTracks(); ++i) {
352 sp<MetaData> meta = extractor->getTrackMetaData(i);
353
354 int32_t bitrate;
355 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
356 totalBitRate = -1;
357 break;
358 }
359
360 totalBitRate += bitrate;
361 }
362
363 mBitrate = totalBitRate;
364
365 LOGV("mBitrate = %lld bits/sec", mBitrate);
366
Andreas Huber27366fc2009-11-20 09:32:46 -0800367 bool haveAudio = false;
368 bool haveVideo = false;
369 for (size_t i = 0; i < extractor->countTracks(); ++i) {
370 sp<MetaData> meta = extractor->getTrackMetaData(i);
371
372 const char *mime;
373 CHECK(meta->findCString(kKeyMIMEType, &mime));
374
375 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800376 setVideoSource(extractor->getTrack(i));
377 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800378 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800379 setAudioSource(extractor->getTrack(i));
380 haveAudio = true;
Andreas Huber9fee0b22010-09-03 14:09:21 -0700381
Andreas Huber1913c1a2010-10-04 11:09:31 -0700382 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
383 // Only do this for vorbis audio, none of the other audio
384 // formats even support this ringtone specific hack and
385 // retrieving the metadata on some extractors may turn out
386 // to be very expensive.
387 sp<MetaData> fileMeta = extractor->getMetaData();
388 int32_t loop;
389 if (fileMeta != NULL
390 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
391 mFlags |= AUTO_LOOPING;
392 }
Andreas Huber9fee0b22010-09-03 14:09:21 -0700393 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800394 }
395
396 if (haveAudio && haveVideo) {
397 break;
398 }
399 }
400
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700401 if (!haveAudio && !haveVideo) {
402 return UNKNOWN_ERROR;
403 }
404
405 mExtractorFlags = extractor->flags();
406
407 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800408}
409
410void AwesomePlayer::reset() {
411 Mutex::Autolock autoLock(mLock);
412 reset_l();
413}
414
415void AwesomePlayer::reset_l() {
Gloria Wangd5770912010-06-22 13:55:38 -0700416 if (mDecryptHandle != NULL) {
417 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
418 Playback::STOP, 0);
Gloria Wangc2c22e72010-11-01 15:53:16 -0700419 mDrmManagerClient->closeDecryptSession(mDecryptHandle);
Gloria Wangd5770912010-06-22 13:55:38 -0700420 mDecryptHandle = NULL;
421 mDrmManagerClient = NULL;
422 }
423
Andreas Huberedbb4d82010-03-12 08:59:22 -0800424 if (mFlags & PREPARING) {
425 mFlags |= PREPARE_CANCELLED;
426 if (mConnectingDataSource != NULL) {
427 LOGI("interrupting the connection process");
428 mConnectingDataSource->disconnect();
429 }
Andreas Hubereaf2c5a2010-10-19 12:18:51 -0700430
431 if (mFlags & PREPARING_CONNECTED) {
432 // We are basically done preparing, we're just buffering
433 // enough data to start playback, we can safely interrupt that.
434 finishAsyncPrepare_l();
435 }
Andreas Huberedbb4d82010-03-12 08:59:22 -0800436 }
437
Andreas Huberffdf4782010-02-09 14:05:43 -0800438 while (mFlags & PREPARING) {
439 mPreparedCondition.wait(mLock);
440 }
441
Andreas Huber27366fc2009-11-20 09:32:46 -0800442 cancelPlayerEvents();
443
Andreas Huber4d61f602010-06-10 11:17:50 -0700444 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800445 mAudioTrack.clear();
446 mVideoTrack.clear();
447
Andreas Huberba7ec912010-02-12 10:42:02 -0800448 // Shutdown audio first, so that the respone to the reset request
449 // appears to happen instantaneously as far as the user is concerned
450 // If we did this later, audio would continue playing while we
451 // shutdown the video-related resources and the player appear to
452 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800453 if (mAudioPlayer == NULL && mAudioSource != NULL) {
454 // If we had an audio player, it would have effectively
455 // taken possession of the audio source and stopped it when
456 // _it_ is stopped. Otherwise this is still our responsibility.
457 mAudioSource->stop();
458 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800459 mAudioSource.clear();
460
Andreas Huberba7ec912010-02-12 10:42:02 -0800461 mTimeSource = NULL;
462
463 delete mAudioPlayer;
464 mAudioPlayer = NULL;
465
Andreas Huber3522b5a52010-01-22 14:36:53 -0800466 mVideoRenderer.clear();
467
Andreas Huber27366fc2009-11-20 09:32:46 -0800468 if (mLastVideoBuffer) {
469 mLastVideoBuffer->release();
470 mLastVideoBuffer = NULL;
471 }
472
473 if (mVideoBuffer) {
474 mVideoBuffer->release();
475 mVideoBuffer = NULL;
476 }
477
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700478 if (mRTSPController != NULL) {
479 mRTSPController->disconnect();
480 mRTSPController.clear();
481 }
482
Andreas Huber57648e42010-08-04 10:14:30 -0700483 mRTPPusher.clear();
484 mRTCPPusher.clear();
485 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700486
Andreas Huber27366fc2009-11-20 09:32:46 -0800487 if (mVideoSource != NULL) {
488 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800489
490 // The following hack is necessary to ensure that the OMX
491 // component is completely released by the time we may try
492 // to instantiate it again.
493 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800494 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800495 while (tmp.promote() != NULL) {
496 usleep(1000);
497 }
498 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800499 }
500
Andreas Huber27366fc2009-11-20 09:32:46 -0800501 mDurationUs = -1;
502 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700503 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800504 mVideoWidth = mVideoHeight = -1;
505 mTimeSourceDeltaUs = 0;
506 mVideoTimeUs = 0;
507
508 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700509 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800510 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800511
Andreas Huberffdf4782010-02-09 14:05:43 -0800512 mUri.setTo("");
513 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800514
515 mFileSource.clear();
516
517 delete mSuspensionState;
518 mSuspensionState = NULL;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700519
520 mBitrate = -1;
Andreas Huber27366fc2009-11-20 09:32:46 -0800521}
522
Andreas Huber6be780e2010-02-08 14:40:30 -0800523void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800524 if (mListener != NULL) {
525 sp<MediaPlayerBase> listener = mListener.promote();
526
527 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800528 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800529 }
530 }
531}
532
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700533bool AwesomePlayer::getBitrate(int64_t *bitrate) {
534 off_t size;
535 if (mDurationUs >= 0 && mCachedSource != NULL
536 && mCachedSource->getSize(&size) == OK) {
537 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
538 return true;
539 }
540
541 if (mBitrate >= 0) {
542 *bitrate = mBitrate;
543 return true;
544 }
545
546 *bitrate = 0;
547
548 return false;
549}
550
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700551// Returns true iff cached duration is available/applicable.
552bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700553 int64_t bitrate;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700554
555 if (mRTSPController != NULL) {
556 *durationUs = mRTSPController->getQueueDurationUs(eos);
557 return true;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700558 } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700559 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
560 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
561 return true;
562 }
563
564 return false;
565}
566
Andreas Huber10b920c2010-11-11 15:37:17 -0800567void AwesomePlayer::ensureCacheIsFetching_l() {
568 if (mCachedSource != NULL) {
569 mCachedSource->resumeFetchingIfNecessary();
570 }
571}
572
Andreas Huberb9e63832010-01-26 16:20:10 -0800573void AwesomePlayer::onBufferingUpdate() {
574 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800575 if (!mBufferingEventPending) {
576 return;
577 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800578 mBufferingEventPending = false;
579
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700580 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700581 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700582 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700583
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700584 if (eos) {
585 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
Andreas Huber05f67872010-10-04 11:36:39 -0700586 if (mFlags & PREPARING) {
587 LOGV("cache has reached EOS, prepare is done.");
588 finishAsyncPrepare_l();
589 }
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700590 } else {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700591 int64_t bitrate;
592 if (getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700593 size_t cachedSize = mCachedSource->cachedSize();
594 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
595
596 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
597 if (percentage > 100) {
598 percentage = 100;
599 }
600
601 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
602 } else {
603 // We don't know the bitrate of the stream, use absolute size
604 // limits to maintain the cache.
605
Andreas Huber54d09722010-10-12 11:34:37 -0700606 const size_t kLowWaterMarkBytes = 40000;
607 const size_t kHighWaterMarkBytes = 200000;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700608
609 if ((mFlags & PLAYING) && !eos
610 && (cachedDataRemaining < kLowWaterMarkBytes)) {
611 LOGI("cache is running low (< %d) , pausing.",
612 kLowWaterMarkBytes);
613 mFlags |= CACHE_UNDERRUN;
614 pause_l();
Andreas Huber10b920c2010-11-11 15:37:17 -0800615 ensureCacheIsFetching_l();
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700616 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
617 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
618 if (mFlags & CACHE_UNDERRUN) {
619 LOGI("cache has filled up (> %d), resuming.",
620 kHighWaterMarkBytes);
621 mFlags &= ~CACHE_UNDERRUN;
622 play_l();
623 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
624 } else if (mFlags & PREPARING) {
625 LOGV("cache has filled up (> %d), prepare is done",
626 kHighWaterMarkBytes);
627 finishAsyncPrepare_l();
628 }
629 }
630 }
631 }
632 }
633
634 int64_t cachedDurationUs;
635 bool eos;
636 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber10b920c2010-11-11 15:37:17 -0800637 LOGV("cachedDurationUs = %.2f secs, eos=%d",
638 cachedDurationUs / 1E6, eos);
639
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700640 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700641 && (cachedDurationUs < kLowWaterMarkUs)) {
642 LOGI("cache is running low (%.2f secs) , pausing.",
643 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700644 mFlags |= CACHE_UNDERRUN;
645 pause_l();
Andreas Huber10b920c2010-11-11 15:37:17 -0800646 ensureCacheIsFetching_l();
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700647 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700648 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
649 if (mFlags & CACHE_UNDERRUN) {
650 LOGI("cache has filled up (%.2f secs), resuming.",
651 cachedDurationUs / 1E6);
652 mFlags &= ~CACHE_UNDERRUN;
653 play_l();
654 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
655 } else if (mFlags & PREPARING) {
656 LOGV("cache has filled up (%.2f secs), prepare is done",
657 cachedDurationUs / 1E6);
658 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700659 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700660 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800661 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700662
Andreas Huber4d61f602010-06-10 11:17:50 -0700663 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800664}
665
Andreas Huber4c19bf92010-09-08 14:32:20 -0700666void AwesomePlayer::partial_reset_l() {
667 // Only reset the video renderer and shut down the video decoder.
668 // Then instantiate a new video decoder and resume video playback.
669
670 mVideoRenderer.clear();
671
672 if (mLastVideoBuffer) {
673 mLastVideoBuffer->release();
674 mLastVideoBuffer = NULL;
675 }
676
677 if (mVideoBuffer) {
678 mVideoBuffer->release();
679 mVideoBuffer = NULL;
680 }
681
682 {
683 mVideoSource->stop();
684
685 // The following hack is necessary to ensure that the OMX
686 // component is completely released by the time we may try
687 // to instantiate it again.
688 wp<MediaSource> tmp = mVideoSource;
689 mVideoSource.clear();
690 while (tmp.promote() != NULL) {
691 usleep(1000);
692 }
693 IPCThreadState::self()->flushCommands();
694 }
695
696 CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
697}
698
Andreas Huber27366fc2009-11-20 09:32:46 -0800699void AwesomePlayer::onStreamDone() {
700 // Posted whenever any stream finishes playing.
701
702 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800703 if (!mStreamDoneEventPending) {
704 return;
705 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800706 mStreamDoneEventPending = false;
707
Andreas Huber4c19bf92010-09-08 14:32:20 -0700708 if (mStreamDoneStatus == INFO_DISCONTINUITY) {
709 // This special status is returned because an http live stream's
710 // video stream switched to a different bandwidth at this point
711 // and future data may have been encoded using different parameters.
712 // This requires us to shutdown the video decoder and reinstantiate
713 // a fresh one.
714
715 LOGV("INFO_DISCONTINUITY");
716
717 CHECK(mVideoSource != NULL);
718
719 partial_reset_l();
720 postVideoEvent_l();
721 return;
722 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Andreas Huber971305d2010-07-07 13:35:27 -0700723 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
724
725 notifyListener_l(
726 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
727
Andreas Huberc743f452010-10-05 10:25:34 -0700728 pause_l(true /* at eos */);
Andreas Huber971305d2010-07-07 13:35:27 -0700729
730 mFlags |= AT_EOS;
731 return;
732 }
733
734 const bool allDone =
735 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
736 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
737
738 if (!allDone) {
739 return;
740 }
741
Andreas Huber9fee0b22010-09-03 14:09:21 -0700742 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800743 seekTo_l(0);
744
Andreas Huber7085b6842010-02-03 16:02:02 -0800745 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800746 postVideoEvent_l();
747 }
748 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700749 LOGV("MEDIA_PLAYBACK_COMPLETE");
750 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800751
Andreas Huberc743f452010-10-05 10:25:34 -0700752 pause_l(true /* at eos */);
Andreas Huber406a18b2010-02-18 16:45:13 -0800753
754 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800755 }
756}
757
758status_t AwesomePlayer::play() {
759 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700760
761 mFlags &= ~CACHE_UNDERRUN;
762
Andreas Huberba7ec912010-02-12 10:42:02 -0800763 return play_l();
764}
Andreas Huber27366fc2009-11-20 09:32:46 -0800765
Andreas Huberba7ec912010-02-12 10:42:02 -0800766status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800767 if (mFlags & PLAYING) {
768 return OK;
769 }
770
Andreas Huberffdf4782010-02-09 14:05:43 -0800771 if (!(mFlags & PREPARED)) {
772 status_t err = prepare_l();
773
774 if (err != OK) {
775 return err;
776 }
777 }
778
Andreas Huber27366fc2009-11-20 09:32:46 -0800779 mFlags |= PLAYING;
780 mFlags |= FIRST_FRAME;
781
Andreas Huberc1d5c922009-12-10 15:49:04 -0800782 bool deferredAudioSeek = false;
783
Andreas Huber27366fc2009-11-20 09:32:46 -0800784 if (mAudioSource != NULL) {
785 if (mAudioPlayer == NULL) {
786 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700787 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800788 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800789
790 // We've already started the MediaSource in order to enable
791 // the prefetcher to read its data.
792 status_t err = mAudioPlayer->start(
793 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800794
795 if (err != OK) {
796 delete mAudioPlayer;
797 mAudioPlayer = NULL;
798
799 mFlags &= ~(PLAYING | FIRST_FRAME);
800
801 return err;
802 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800803
Andreas Huber27366fc2009-11-20 09:32:46 -0800804 mTimeSource = mAudioPlayer;
805
Andreas Huberc1d5c922009-12-10 15:49:04 -0800806 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800807
808 mWatchForAudioSeekComplete = false;
809 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800810 }
811 } else {
812 mAudioPlayer->resume();
813 }
814 }
815
816 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700817 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800818 }
819
820 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800821 // Kick off video playback
822 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800823 }
824
Andreas Huberc1d5c922009-12-10 15:49:04 -0800825 if (deferredAudioSeek) {
826 // If there was a seek request while we were paused
827 // and we're just starting up again, honor the request now.
828 seekAudioIfNecessary_l();
829 }
830
Andreas Huber406a18b2010-02-18 16:45:13 -0800831 if (mFlags & AT_EOS) {
832 // Legacy behaviour, if a stream finishes playing and then
833 // is started again, we play from the start...
834 seekTo_l(0);
835 }
836
Gloria Wangd5770912010-06-22 13:55:38 -0700837 if (mDecryptHandle != NULL) {
838 int64_t position;
839 getPosition(&position);
840 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
841 Playback::START, position / 1000);
842 }
843
Andreas Huber27366fc2009-11-20 09:32:46 -0800844 return OK;
845}
846
Andreas Hubere3c01832010-08-16 08:49:37 -0700847void AwesomePlayer::notifyVideoSize_l() {
848 sp<MetaData> meta = mVideoSource->getFormat();
849
850 int32_t decodedWidth, decodedHeight;
851 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
852 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
853
854 notifyListener_l(MEDIA_SET_VIDEO_SIZE, decodedWidth, decodedHeight);
855}
856
Andreas Huber27366fc2009-11-20 09:32:46 -0800857void AwesomePlayer::initRenderer_l() {
Andreas Hubere3c01832010-08-16 08:49:37 -0700858 if (mSurface != NULL || mISurface != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800859 sp<MetaData> meta = mVideoSource->getFormat();
860
861 int32_t format;
862 const char *component;
863 int32_t decodedWidth, decodedHeight;
864 CHECK(meta->findInt32(kKeyColorFormat, &format));
865 CHECK(meta->findCString(kKeyDecoderComponent, &component));
866 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
867 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
868
Andreas Hubera67d5382009-12-10 15:32:12 -0800869 mVideoRenderer.clear();
870
871 // Must ensure that mVideoRenderer's destructor is actually executed
872 // before creating a new one.
873 IPCThreadState::self()->flushCommands();
874
Andreas Hubere3c01832010-08-16 08:49:37 -0700875 if (mSurface != NULL) {
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700876 if (strncmp(component, "OMX.", 4) == 0) {
877 // Hardware decoders avoid the CPU color conversion by decoding
878 // directly to ANativeBuffers, so we must use a renderer that
879 // just pushes those buffers to the ANativeWindow.
880 mVideoRenderer = new AwesomeNativeWindowRenderer(mSurface);
881 } else {
882 // Other decoders are instantiated locally and as a consequence
883 // allocate their buffers in local address space. This renderer
884 // then performs a color conversion and copy to get the data
885 // into the ANativeBuffer.
886 mVideoRenderer = new AwesomeLocalRenderer(
887 false, // previewOnly
888 component,
889 (OMX_COLOR_FORMATTYPE)format,
890 mISurface,
891 mSurface,
892 mVideoWidth, mVideoHeight,
893 decodedWidth, decodedHeight);
894 }
Andreas Hubere3c01832010-08-16 08:49:37 -0700895 } else {
Andreas Huber1314e732009-12-14 14:18:22 -0800896 // Our OMX codecs allocate buffers on the media_server side
897 // therefore they require a remote IOMXRenderer that knows how
898 // to display them.
899 mVideoRenderer = new AwesomeRemoteRenderer(
900 mClient.interface()->createRenderer(
901 mISurface, component,
902 (OMX_COLOR_FORMATTYPE)format,
903 decodedWidth, decodedHeight,
904 mVideoWidth, mVideoHeight));
Andreas Huber1314e732009-12-14 14:18:22 -0800905 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800906 }
907}
908
909status_t AwesomePlayer::pause() {
910 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700911
912 mFlags &= ~CACHE_UNDERRUN;
913
Andreas Huber27366fc2009-11-20 09:32:46 -0800914 return pause_l();
915}
916
Andreas Huberc743f452010-10-05 10:25:34 -0700917status_t AwesomePlayer::pause_l(bool at_eos) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800918 if (!(mFlags & PLAYING)) {
919 return OK;
920 }
921
Andreas Huberb9e63832010-01-26 16:20:10 -0800922 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800923
924 if (mAudioPlayer != NULL) {
Andreas Huberc743f452010-10-05 10:25:34 -0700925 if (at_eos) {
926 // If we played the audio stream to completion we
927 // want to make sure that all samples remaining in the audio
928 // track's queue are played out.
929 mAudioPlayer->pause(true /* playPendingSamples */);
930 } else {
931 mAudioPlayer->pause();
932 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800933 }
934
935 mFlags &= ~PLAYING;
936
Gloria Wangd5770912010-06-22 13:55:38 -0700937 if (mDecryptHandle != NULL) {
938 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
939 Playback::PAUSE, 0);
940 }
941
Andreas Huber27366fc2009-11-20 09:32:46 -0800942 return OK;
943}
944
945bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700946 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800947}
948
949void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
950 Mutex::Autolock autoLock(mLock);
951
952 mISurface = isurface;
953}
954
Andreas Hubere3c01832010-08-16 08:49:37 -0700955void AwesomePlayer::setSurface(const sp<Surface> &surface) {
956 Mutex::Autolock autoLock(mLock);
957
958 mSurface = surface;
959}
960
Andreas Huber27366fc2009-11-20 09:32:46 -0800961void AwesomePlayer::setAudioSink(
962 const sp<MediaPlayerBase::AudioSink> &audioSink) {
963 Mutex::Autolock autoLock(mLock);
964
965 mAudioSink = audioSink;
966}
967
968status_t AwesomePlayer::setLooping(bool shouldLoop) {
969 Mutex::Autolock autoLock(mLock);
970
971 mFlags = mFlags & ~LOOPING;
972
973 if (shouldLoop) {
974 mFlags |= LOOPING;
975 }
976
977 return OK;
978}
979
980status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700981 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800982
983 if (mDurationUs < 0) {
984 return UNKNOWN_ERROR;
985 }
986
987 *durationUs = mDurationUs;
988
989 return OK;
990}
991
992status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -0700993 if (mRTSPController != NULL) {
994 *positionUs = mRTSPController->getNormalPlayTimeUs();
995 }
996 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700997 *positionUs = mSeekTimeUs;
998 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700999 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001000 *positionUs = mVideoTimeUs;
1001 } else if (mAudioPlayer != NULL) {
1002 *positionUs = mAudioPlayer->getMediaTimeUs();
1003 } else {
1004 *positionUs = 0;
1005 }
1006
1007 return OK;
1008}
1009
1010status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber10b9b3f2010-10-08 10:16:24 -07001011 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001012 Mutex::Autolock autoLock(mLock);
1013 return seekTo_l(timeUs);
1014 }
1015
1016 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -08001017}
1018
Andreas Huber0c46b692010-10-08 15:21:08 -07001019// static
1020void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
1021 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
1022}
1023
1024void AwesomePlayer::onRTSPSeekDone() {
1025 notifyListener_l(MEDIA_SEEK_COMPLETE);
1026 mSeekNotificationSent = true;
1027}
1028
Andreas Huber27366fc2009-11-20 09:32:46 -08001029status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001030 if (mRTSPController != NULL) {
Andreas Huber0c46b692010-10-08 15:21:08 -07001031 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001032 return OK;
1033 }
1034
Andreas Huber4d61f602010-06-10 11:17:50 -07001035 if (mFlags & CACHE_UNDERRUN) {
1036 mFlags &= ~CACHE_UNDERRUN;
1037 play_l();
1038 }
1039
Andreas Huber27366fc2009-11-20 09:32:46 -08001040 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001041 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001042 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001043 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -08001044
1045 seekAudioIfNecessary_l();
1046
Andreas Huber8e2b9412010-03-31 09:40:15 -07001047 if (!(mFlags & PLAYING)) {
1048 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
1049 " immediately.");
1050
1051 notifyListener_l(MEDIA_SEEK_COMPLETE);
1052 mSeekNotificationSent = true;
1053 }
1054
Andreas Huber27366fc2009-11-20 09:32:46 -08001055 return OK;
1056}
1057
1058void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -08001059 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001060 mAudioPlayer->seekTo(mSeekTimeUs);
1061
Andreas Huber70d10c02010-02-03 11:37:29 -08001062 mWatchForAudioSeekComplete = true;
1063 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001064 mSeekNotificationSent = false;
Gloria Wangd5770912010-06-22 13:55:38 -07001065
1066 if (mDecryptHandle != NULL) {
1067 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1068 Playback::PAUSE, 0);
1069 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1070 Playback::START, mSeekTimeUs / 1000);
1071 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001072 }
1073}
1074
1075status_t AwesomePlayer::getVideoDimensions(
1076 int32_t *width, int32_t *height) const {
1077 Mutex::Autolock autoLock(mLock);
1078
1079 if (mVideoWidth < 0 || mVideoHeight < 0) {
1080 return UNKNOWN_ERROR;
1081 }
1082
1083 *width = mVideoWidth;
1084 *height = mVideoHeight;
1085
1086 return OK;
1087}
1088
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001089void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1090 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001091
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001092 mAudioTrack = source;
1093}
1094
1095status_t AwesomePlayer::initAudioDecoder() {
1096 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -08001097
1098 const char *mime;
1099 CHECK(meta->findCString(kKeyMIMEType, &mime));
1100
1101 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001102 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -08001103 } else {
1104 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001105 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -08001106 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001107 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -08001108 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001109
1110 if (mAudioSource != NULL) {
1111 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001112 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001113 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001114 if (mDurationUs < 0 || durationUs > mDurationUs) {
1115 mDurationUs = durationUs;
1116 }
1117 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001118
Andreas Huber3c78a1b2010-05-13 09:15:21 -07001119 status_t err = mAudioSource->start();
1120
1121 if (err != OK) {
1122 mAudioSource.clear();
1123 return err;
1124 }
Andreas Huberd0332ad2010-04-12 16:05:57 -07001125 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1126 // For legacy reasons we're simply going to ignore the absence
1127 // of an audio decoder for QCELP instead of aborting playback
1128 // altogether.
1129 return OK;
1130 }
Andreas Huberdc9927d2010-03-08 15:46:13 -08001131
Andreas Huber27366fc2009-11-20 09:32:46 -08001132 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1133}
1134
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001135void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1136 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001137
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001138 mVideoTrack = source;
1139}
1140
Andreas Huber4c19bf92010-09-08 14:32:20 -07001141status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001142 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001143 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -08001144 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -07001145 mVideoTrack,
Jamie Gennis58a36ad2010-10-07 14:08:38 -07001146 NULL, flags, mSurface);
Andreas Huber27366fc2009-11-20 09:32:46 -08001147
1148 if (mVideoSource != NULL) {
1149 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001150 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001151 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001152 if (mDurationUs < 0 || durationUs > mDurationUs) {
1153 mDurationUs = durationUs;
1154 }
1155 }
1156
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001157 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
1158 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -08001159
Andreas Huber1919e5a2010-05-20 10:37:06 -07001160 status_t err = mVideoSource->start();
1161
1162 if (err != OK) {
1163 mVideoSource.clear();
1164 return err;
1165 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001166 }
1167
1168 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1169}
1170
Andreas Huber4d450a82010-10-19 09:34:44 -07001171void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1172 if (!mSeeking) {
1173 return;
1174 }
1175
1176 if (mAudioPlayer != NULL) {
Jamie Gennis6913c612010-10-20 15:55:43 -07001177 LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
Andreas Huber4d450a82010-10-19 09:34:44 -07001178
1179 // If we don't have a video time, seek audio to the originally
1180 // requested seek time instead.
1181
1182 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1183 mAudioPlayer->resume();
1184 mWatchForAudioSeekComplete = true;
1185 mWatchForAudioEOS = true;
1186 } else if (!mSeekNotificationSent) {
1187 // If we're playing video only, report seek complete now,
1188 // otherwise audio player will notify us later.
1189 notifyListener_l(MEDIA_SEEK_COMPLETE);
1190 }
1191
1192 mFlags |= FIRST_FRAME;
1193 mSeeking = false;
1194 mSeekNotificationSent = false;
Gloria Wang3f9a8192010-10-29 14:50:17 -07001195
1196 if (mDecryptHandle != NULL) {
1197 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1198 Playback::PAUSE, 0);
1199 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1200 Playback::START, videoTimeUs / 1000);
1201 }
Andreas Huber4d450a82010-10-19 09:34:44 -07001202}
1203
Andreas Huber6be780e2010-02-08 14:40:30 -08001204void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -08001205 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -08001206 if (!mVideoEventPending) {
1207 // The event has been cancelled in reset_l() but had already
1208 // been scheduled for execution at that time.
1209 return;
1210 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001211 mVideoEventPending = false;
1212
1213 if (mSeeking) {
1214 if (mLastVideoBuffer) {
1215 mLastVideoBuffer->release();
1216 mLastVideoBuffer = NULL;
1217 }
1218
1219 if (mVideoBuffer) {
1220 mVideoBuffer->release();
1221 mVideoBuffer = NULL;
1222 }
Andreas Huber4d61f602010-06-10 11:17:50 -07001223
1224 if (mCachedSource != NULL && mAudioSource != NULL) {
1225 // We're going to seek the video source first, followed by
1226 // the audio source.
1227 // In order to avoid jumps in the DataSource offset caused by
1228 // the audio codec prefetching data from the old locations
1229 // while the video codec is already reading data from the new
1230 // locations, we'll "pause" the audio source, causing it to
1231 // stop reading input data until a subsequent seek.
1232
1233 if (mAudioPlayer != NULL) {
1234 mAudioPlayer->pause();
1235 }
1236 mAudioSource->pause();
1237 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001238 }
1239
1240 if (!mVideoBuffer) {
1241 MediaSource::ReadOptions options;
1242 if (mSeeking) {
1243 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1244
Andreas Huber6624c9f2010-07-20 15:04:28 -07001245 options.setSeekTo(
1246 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001247 }
1248 for (;;) {
1249 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001250 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001251
1252 if (err != OK) {
1253 CHECK_EQ(mVideoBuffer, NULL);
1254
1255 if (err == INFO_FORMAT_CHANGED) {
1256 LOGV("VideoSource signalled format change.");
1257
Andreas Hubere3c01832010-08-16 08:49:37 -07001258 notifyVideoSize_l();
1259
Andreas Huber7085b6842010-02-03 16:02:02 -08001260 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001261 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001262 initRenderer_l();
1263 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001264 continue;
1265 }
1266
Andreas Huber4d450a82010-10-19 09:34:44 -07001267 // So video playback is complete, but we may still have
1268 // a seek request pending that needs to be applied
1269 // to the audio track.
1270 if (mSeeking) {
1271 LOGV("video stream ended while seeking!");
1272 }
1273 finishSeekIfNecessary(-1);
1274
Andreas Huber971305d2010-07-07 13:35:27 -07001275 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001276 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001277 return;
1278 }
1279
Andreas Hubera67d5382009-12-10 15:32:12 -08001280 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001281 // Some decoders, notably the PV AVC software decoder
1282 // return spurious empty buffers that we just want to ignore.
1283
Andreas Hubera67d5382009-12-10 15:32:12 -08001284 mVideoBuffer->release();
1285 mVideoBuffer = NULL;
1286 continue;
1287 }
1288
Andreas Huber27366fc2009-11-20 09:32:46 -08001289 break;
1290 }
1291 }
1292
1293 int64_t timeUs;
1294 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1295
Andreas Huber252573c2010-03-26 10:17:17 -07001296 {
1297 Mutex::Autolock autoLock(mMiscStateLock);
1298 mVideoTimeUs = timeUs;
1299 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001300
Andreas Huber614d22c2010-10-29 15:47:52 -07001301 bool wasSeeking = mSeeking;
Andreas Huber4d450a82010-10-19 09:34:44 -07001302 finishSeekIfNecessary(timeUs);
Andreas Huber27366fc2009-11-20 09:32:46 -08001303
Andreas Huber971305d2010-07-07 13:35:27 -07001304 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1305
Andreas Huber27366fc2009-11-20 09:32:46 -08001306 if (mFlags & FIRST_FRAME) {
1307 mFlags &= ~FIRST_FRAME;
1308
Andreas Huber971305d2010-07-07 13:35:27 -07001309 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001310 }
1311
1312 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001313 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001314 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1315 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1316 }
1317
Andreas Huber971305d2010-07-07 13:35:27 -07001318 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001319
1320 int64_t latenessUs = nowUs - timeUs;
1321
Andreas Huber614d22c2010-10-29 15:47:52 -07001322 if (wasSeeking) {
1323 // Let's display the first frame after seeking right away.
1324 latenessUs = 0;
1325 }
1326
Andreas Huberf88f8442010-08-10 11:18:36 -07001327 if (mRTPSession != NULL) {
1328 // We'll completely ignore timestamps for gtalk videochat
1329 // and we'll play incoming video as fast as we get it.
1330 latenessUs = 0;
1331 }
1332
Andreas Huber24b0a952009-11-23 14:02:00 -08001333 if (latenessUs > 40000) {
1334 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001335 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001336
1337 mVideoBuffer->release();
1338 mVideoBuffer = NULL;
1339
1340 postVideoEvent_l();
1341 return;
1342 }
1343
1344 if (latenessUs < -10000) {
1345 // We're more than 10ms early.
1346
1347 postVideoEvent_l(10000);
1348 return;
1349 }
1350
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001351 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1352 mVideoRendererIsPreview = false;
1353
Andreas Huber7085b6842010-02-03 16:02:02 -08001354 initRenderer_l();
1355 }
1356
1357 if (mVideoRenderer != NULL) {
1358 mVideoRenderer->render(mVideoBuffer);
1359 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001360
1361 if (mLastVideoBuffer) {
1362 mLastVideoBuffer->release();
1363 mLastVideoBuffer = NULL;
1364 }
1365 mLastVideoBuffer = mVideoBuffer;
1366 mVideoBuffer = NULL;
1367
1368 postVideoEvent_l();
1369}
1370
1371void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1372 if (mVideoEventPending) {
1373 return;
1374 }
1375
1376 mVideoEventPending = true;
1377 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1378}
1379
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001380void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001381 if (mStreamDoneEventPending) {
1382 return;
1383 }
1384 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001385
1386 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001387 mQueue.postEvent(mStreamDoneEvent);
1388}
1389
Andreas Huberb9e63832010-01-26 16:20:10 -08001390void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001391 if (mBufferingEventPending) {
1392 return;
1393 }
1394 mBufferingEventPending = true;
1395 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1396}
1397
Andreas Huber70d10c02010-02-03 11:37:29 -08001398void AwesomePlayer::postCheckAudioStatusEvent_l() {
1399 if (mAudioStatusEventPending) {
1400 return;
1401 }
1402 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001403 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001404}
1405
1406void AwesomePlayer::onCheckAudioStatus() {
1407 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001408 if (!mAudioStatusEventPending) {
1409 // Event was dispatched and while we were blocking on the mutex,
1410 // has already been cancelled.
1411 return;
1412 }
1413
Andreas Huber70d10c02010-02-03 11:37:29 -08001414 mAudioStatusEventPending = false;
1415
1416 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1417 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001418
1419 if (!mSeekNotificationSent) {
1420 notifyListener_l(MEDIA_SEEK_COMPLETE);
1421 mSeekNotificationSent = true;
1422 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001423
1424 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001425 }
1426
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001427 status_t finalStatus;
1428 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001429 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001430 mFlags |= AUDIO_AT_EOS;
1431 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001432 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001433 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001434}
1435
Andreas Huber6be780e2010-02-08 14:40:30 -08001436status_t AwesomePlayer::prepare() {
1437 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001438 return prepare_l();
1439}
Andreas Huber6be780e2010-02-08 14:40:30 -08001440
Andreas Huberffdf4782010-02-09 14:05:43 -08001441status_t AwesomePlayer::prepare_l() {
1442 if (mFlags & PREPARED) {
1443 return OK;
1444 }
1445
1446 if (mFlags & PREPARING) {
1447 return UNKNOWN_ERROR;
1448 }
1449
1450 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001451 status_t err = prepareAsync_l();
1452
1453 if (err != OK) {
1454 return err;
1455 }
1456
Andreas Huberffdf4782010-02-09 14:05:43 -08001457 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001458 mPreparedCondition.wait(mLock);
1459 }
1460
Andreas Huberffdf4782010-02-09 14:05:43 -08001461 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001462}
1463
1464status_t AwesomePlayer::prepareAsync() {
1465 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001466
1467 if (mFlags & PREPARING) {
1468 return UNKNOWN_ERROR; // async prepare already pending
1469 }
1470
1471 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001472 return prepareAsync_l();
1473}
1474
1475status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001476 if (mFlags & PREPARING) {
1477 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001478 }
1479
Andreas Huber406a18b2010-02-18 16:45:13 -08001480 if (!mQueueStarted) {
1481 mQueue.start();
1482 mQueueStarted = true;
1483 }
1484
Andreas Huberffdf4782010-02-09 14:05:43 -08001485 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001486 mAsyncPrepareEvent = new AwesomeEvent(
1487 this, &AwesomePlayer::onPrepareAsyncEvent);
1488
1489 mQueue.postEvent(mAsyncPrepareEvent);
1490
1491 return OK;
1492}
1493
Andreas Huberffdf4782010-02-09 14:05:43 -08001494status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001495 sp<DataSource> dataSource;
1496
1497 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001498 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001499
1500 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001501 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001502 mLock.lock();
1503
1504 if (err != OK) {
1505 mConnectingDataSource.clear();
1506
1507 LOGI("mConnectingDataSource->connect() returned %d", err);
1508 return err;
1509 }
1510
Andreas Huber4d61f602010-06-10 11:17:50 -07001511#if 0
1512 mCachedSource = new NuCachedSource2(
1513 new ThrottledSource(
1514 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1515#else
1516 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1517#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001518 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001519
1520 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001521 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1522 String8 uri("http://");
1523 uri.append(mUri.string() + 11);
1524
Andreas Huber54d09722010-10-12 11:34:37 -07001525 sp<LiveSource> liveSource = new LiveSource(uri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001526
Andreas Huber54d09722010-10-12 11:34:37 -07001527 mCachedSource = new NuCachedSource2(liveSource);
Andreas Huber4d61f602010-06-10 11:17:50 -07001528 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001529
1530 sp<MediaExtractor> extractor =
1531 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001532
Andreas Huber54d09722010-10-12 11:34:37 -07001533 static_cast<MPEG2TSExtractor *>(extractor.get())
1534 ->setLiveSource(liveSource);
1535
Andreas Huber4d61f602010-06-10 11:17:50 -07001536 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001537 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001538 if (mLooper == NULL) {
1539 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001540 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001541 mLooper->start(
1542 false /* runOnCallingThread */,
1543 false /* canCallJava */,
1544 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001545 }
1546
Mike Dodd8741dfa2010-08-12 16:04:35 -07001547 const char *startOfCodecString = &mUri.string()[13];
1548 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1549 if (startOfSlash1 == NULL) {
1550 return BAD_VALUE;
1551 }
1552 const char *startOfWidthString = &startOfSlash1[1];
1553 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1554 if (startOfSlash2 == NULL) {
1555 return BAD_VALUE;
1556 }
1557 const char *startOfHeightString = &startOfSlash2[1];
1558
1559 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1560 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1561 String8 heightString(startOfHeightString);
1562
Andreas Huber57648e42010-08-04 10:14:30 -07001563#if 0
1564 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1565 mLooper->registerHandler(mRTPPusher);
1566
1567 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1568 mLooper->registerHandler(mRTCPPusher);
1569#endif
1570
1571 mRTPSession = new ARTPSession;
1572 mLooper->registerHandler(mRTPSession);
1573
1574#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001575 // My AMR SDP
1576 static const char *raw =
1577 "v=0\r\n"
1578 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1579 "s=QuickTime\r\n"
1580 "t=0 0\r\n"
1581 "a=range:npt=0-315\r\n"
1582 "a=isma-compliance:2,2.0,2\r\n"
1583 "m=audio 5434 RTP/AVP 97\r\n"
1584 "c=IN IP4 127.0.0.1\r\n"
1585 "b=AS:30\r\n"
1586 "a=rtpmap:97 AMR/8000/1\r\n"
1587 "a=fmtp:97 octet-align\r\n";
1588#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001589 String8 sdp;
1590 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001591 "v=0\r\n"
1592 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1593 "s=QuickTime\r\n"
1594 "t=0 0\r\n"
1595 "a=range:npt=0-315\r\n"
1596 "a=isma-compliance:2,2.0,2\r\n"
1597 "m=video 5434 RTP/AVP 97\r\n"
1598 "c=IN IP4 127.0.0.1\r\n"
1599 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001600 "a=rtpmap:97 %s/90000\r\n"
1601 "a=cliprect:0,0,%s,%s\r\n"
1602 "a=framesize:97 %s-%s\r\n",
1603
1604 codecString.string(),
1605 heightString.string(), widthString.string(),
1606 widthString.string(), heightString.string()
1607 );
1608 const char *raw = sdp.string();
1609
Andreas Huber57648e42010-08-04 10:14:30 -07001610#endif
1611
1612 sp<ASessionDescription> desc = new ASessionDescription;
1613 CHECK(desc->setTo(raw, strlen(raw)));
1614
1615 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1616
1617 if (mRTPPusher != NULL) {
1618 mRTPPusher->start();
1619 }
1620
1621 if (mRTCPPusher != NULL) {
1622 mRTCPPusher->start();
1623 }
1624
1625 CHECK_EQ(mRTPSession->countTracks(), 1u);
1626 sp<MediaSource> source = mRTPSession->trackAt(0);
1627
1628#if 0
1629 bool eos;
1630 while (((APacketSource *)source.get())
1631 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1632 usleep(100000ll);
1633 }
1634#endif
1635
1636 const char *mime;
1637 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1638
1639 if (!strncasecmp("video/", mime, 6)) {
1640 setVideoSource(source);
1641 } else {
1642 CHECK(!strncasecmp("audio/", mime, 6));
1643 setAudioSource(source);
1644 }
1645
1646 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1647
1648 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001649 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1650 if (mLooper == NULL) {
1651 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001652 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001653 mLooper->start();
1654 }
1655 mRTSPController = new ARTSPController(mLooper);
1656 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001657
Andreas Huber7a747b82010-06-07 15:19:40 -07001658 LOGI("ARTSPController::connect returned %d", err);
1659
1660 if (err != OK) {
1661 mRTSPController.clear();
1662 return err;
1663 }
1664
1665 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001666 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001667 } else {
1668 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1669 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001670
1671 if (dataSource == NULL) {
1672 return UNKNOWN_ERROR;
1673 }
1674
1675 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1676
1677 if (extractor == NULL) {
1678 return UNKNOWN_ERROR;
1679 }
1680
Gloria Wangd5770912010-06-22 13:55:38 -07001681 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangc2c22e72010-11-01 15:53:16 -07001682 if (mDecryptHandle != NULL) {
1683 if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
1684 if (DecryptApiType::WV_BASED == mDecryptHandle->decryptApiType) {
1685 LOGD("Setting mCachedSource to NULL for WVM\n");
1686 mCachedSource.clear();
1687 }
1688 } else {
1689 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
1690 }
Gloria Wangd5770912010-06-22 13:55:38 -07001691 }
1692
Andreas Huberffdf4782010-02-09 14:05:43 -08001693 return setDataSource_l(extractor);
1694}
1695
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001696void AwesomePlayer::abortPrepare(status_t err) {
1697 CHECK(err != OK);
1698
1699 if (mIsAsyncPrepare) {
1700 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1701 }
1702
1703 mPrepareResult = err;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001704 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001705 mAsyncPrepareEvent = NULL;
1706 mPreparedCondition.broadcast();
1707}
1708
Andreas Huberf71daba2010-03-24 09:24:40 -07001709// static
1710bool AwesomePlayer::ContinuePreparation(void *cookie) {
1711 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1712
1713 return (me->mFlags & PREPARE_CANCELLED) == 0;
1714}
1715
Andreas Huber6be780e2010-02-08 14:40:30 -08001716void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001717 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001718
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001719 if (mFlags & PREPARE_CANCELLED) {
1720 LOGI("prepare was cancelled before doing anything");
1721 abortPrepare(UNKNOWN_ERROR);
1722 return;
1723 }
1724
1725 if (mUri.size() > 0) {
1726 status_t err = finishSetDataSource_l();
1727
1728 if (err != OK) {
1729 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001730 return;
1731 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001732 }
1733
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001734 if (mVideoTrack != NULL && mVideoSource == NULL) {
1735 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001736
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001737 if (err != OK) {
1738 abortPrepare(err);
1739 return;
1740 }
1741 }
1742
1743 if (mAudioTrack != NULL && mAudioSource == NULL) {
1744 status_t err = initAudioDecoder();
1745
1746 if (err != OK) {
1747 abortPrepare(err);
1748 return;
1749 }
1750 }
1751
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001752 mFlags |= PREPARING_CONNECTED;
1753
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001754 if (mCachedSource != NULL || mRTSPController != NULL) {
1755 postBufferingEvent_l();
1756 } else {
1757 finishAsyncPrepare_l();
1758 }
1759}
1760
1761void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001762 if (mIsAsyncPrepare) {
Andreas Hubere3c01832010-08-16 08:49:37 -07001763 if (mVideoSource == NULL) {
Andreas Huberffdf4782010-02-09 14:05:43 -08001764 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1765 } else {
Andreas Hubere3c01832010-08-16 08:49:37 -07001766 notifyVideoSize_l();
Andreas Huberffdf4782010-02-09 14:05:43 -08001767 }
1768
1769 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001770 }
1771
Andreas Huberffdf4782010-02-09 14:05:43 -08001772 mPrepareResult = OK;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001773 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001774 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001775 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001776 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001777}
1778
Andreas Huberba7ec912010-02-12 10:42:02 -08001779status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001780 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001781 Mutex::Autolock autoLock(mLock);
1782
1783 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001784 if (mLastVideoBuffer == NULL) {
1785 //go into here if video is suspended again
1786 //after resuming without being played between
1787 //them
1788 SuspensionState *state = mSuspensionState;
1789 mSuspensionState = NULL;
1790 reset_l();
1791 mSuspensionState = state;
1792 return OK;
1793 }
1794
1795 delete mSuspensionState;
1796 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001797 }
1798
Andreas Huberedbb4d82010-03-12 08:59:22 -08001799 if (mFlags & PREPARING) {
1800 mFlags |= PREPARE_CANCELLED;
1801 if (mConnectingDataSource != NULL) {
1802 LOGI("interrupting the connection process");
1803 mConnectingDataSource->disconnect();
1804 }
1805 }
1806
Andreas Huberba7ec912010-02-12 10:42:02 -08001807 while (mFlags & PREPARING) {
1808 mPreparedCondition.wait(mLock);
1809 }
1810
1811 SuspensionState *state = new SuspensionState;
1812 state->mUri = mUri;
1813 state->mUriHeaders = mUriHeaders;
1814 state->mFileSource = mFileSource;
1815
Andreas Huber9fee0b22010-09-03 14:09:21 -07001816 state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001817 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001818
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001819 if (mLastVideoBuffer) {
1820 size_t size = mLastVideoBuffer->range_length();
Andreas Huber1e194162010-10-06 16:43:57 -07001821
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001822 if (size) {
Andreas Huber1e194162010-10-06 16:43:57 -07001823 int32_t unreadable;
1824 if (!mLastVideoBuffer->meta_data()->findInt32(
1825 kKeyIsUnreadable, &unreadable)
1826 || unreadable == 0) {
1827 state->mLastVideoFrameSize = size;
1828 state->mLastVideoFrame = malloc(size);
1829 memcpy(state->mLastVideoFrame,
1830 (const uint8_t *)mLastVideoBuffer->data()
1831 + mLastVideoBuffer->range_offset(),
1832 size);
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001833
Andreas Huber1e194162010-10-06 16:43:57 -07001834 state->mVideoWidth = mVideoWidth;
1835 state->mVideoHeight = mVideoHeight;
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001836
Andreas Huber1e194162010-10-06 16:43:57 -07001837 sp<MetaData> meta = mVideoSource->getFormat();
1838 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1839 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1840 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1841 } else {
1842 LOGV("Unable to save last video frame, we have no access to "
1843 "the decoded video data.");
1844 }
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001845 }
1846 }
1847
Andreas Huberba7ec912010-02-12 10:42:02 -08001848 reset_l();
1849
1850 mSuspensionState = state;
1851
1852 return OK;
1853}
1854
1855status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001856 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001857 Mutex::Autolock autoLock(mLock);
1858
1859 if (mSuspensionState == NULL) {
1860 return INVALID_OPERATION;
1861 }
1862
1863 SuspensionState *state = mSuspensionState;
1864 mSuspensionState = NULL;
1865
1866 status_t err;
1867 if (state->mFileSource != NULL) {
1868 err = setDataSource_l(state->mFileSource);
1869
1870 if (err == OK) {
1871 mFileSource = state->mFileSource;
1872 }
1873 } else {
1874 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1875 }
1876
1877 if (err != OK) {
1878 delete state;
1879 state = NULL;
1880
1881 return err;
1882 }
1883
1884 seekTo_l(state->mPositionUs);
1885
Andreas Huber9fee0b22010-09-03 14:09:21 -07001886 mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001887
Andreas Hubere3c01832010-08-16 08:49:37 -07001888 if (state->mLastVideoFrame && (mSurface != NULL || mISurface != NULL)) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001889 mVideoRenderer =
1890 new AwesomeLocalRenderer(
1891 true, // previewOnly
1892 "",
1893 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1894 mISurface,
Andreas Hubere3c01832010-08-16 08:49:37 -07001895 mSurface,
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001896 state->mVideoWidth,
1897 state->mVideoHeight,
1898 state->mDecodedWidth,
1899 state->mDecodedHeight);
1900
1901 mVideoRendererIsPreview = true;
1902
1903 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1904 state->mLastVideoFrame, state->mLastVideoFrameSize);
1905 }
1906
Andreas Huberba7ec912010-02-12 10:42:02 -08001907 if (state->mFlags & PLAYING) {
1908 play_l();
1909 }
1910
Gloria Wangb19da8e2010-04-12 17:13:06 -07001911 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001912 state = NULL;
1913
1914 return OK;
1915}
1916
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001917uint32_t AwesomePlayer::flags() const {
1918 return mExtractorFlags;
1919}
1920
Andreas Huber2b359ed2010-09-28 11:56:39 -07001921void AwesomePlayer::postAudioEOS() {
1922 postCheckAudioStatusEvent_l();
1923}
1924
1925void AwesomePlayer::postAudioSeekComplete() {
1926 postCheckAudioStatusEvent_l();
1927}
1928
Andreas Huber27366fc2009-11-20 09:32:46 -08001929} // namespace android