blob: 7b9dbb7809ab1e6ee43f1f9262c7a4ce5381a82d [file] [log] [blame]
Andreas Huberf9334412010-12-15 15:17:42 -08001/*
2 * Copyright (C) 2010 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 "NuPlayerRenderer"
19#include <utils/Log.h>
20
21#include "NuPlayerRenderer.h"
22
Lajos Molnar274084f2014-09-29 16:36:37 -070023#include <cutils/properties.h>
24
Andreas Huberf9334412010-12-15 15:17:42 -080025#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
Andreas Huber5bc087c2010-12-23 10:27:40 -080027#include <media/stagefright/foundation/AMessage.h>
Ronghua Wua73d9e02014-10-08 15:13:29 -070028#include <media/stagefright/foundation/AUtils.h>
Wei Jiabc2fb722014-07-08 16:37:57 -070029#include <media/stagefright/MediaErrors.h>
30#include <media/stagefright/MetaData.h>
Andreas Huberf9334412010-12-15 15:17:42 -080031
Lajos Molnardc43dfa2014-05-07 15:33:04 -070032#include <VideoFrameScheduler.h>
33
Lajos Molnar09524832014-07-17 14:29:51 -070034#include <inttypes.h>
35
Andreas Huberf9334412010-12-15 15:17:42 -080036namespace android {
37
Ronghua Wuf5b1db12014-09-09 10:11:08 -070038// Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink
39// is closed to allow the audio DSP to power down.
40static const int64_t kOffloadPauseMaxUs = 60000000ll;
41
Andreas Huber714aa7b2011-09-13 08:28:38 -070042// static
43const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
44
Lajos Molnar274084f2014-09-29 16:36:37 -070045static bool sFrameAccurateAVsync = false;
46
47static void readProperties() {
48 char value[PROPERTY_VALUE_MAX];
49 if (property_get("persist.sys.media.avsync", value, NULL)) {
50 sFrameAccurateAVsync =
51 !strcmp("1", value) || !strcasecmp("true", value);
52 }
53}
54
Andreas Huberf9334412010-12-15 15:17:42 -080055NuPlayer::Renderer::Renderer(
56 const sp<MediaPlayerBase::AudioSink> &sink,
Andreas Huberd5e56232013-03-12 11:01:43 -070057 const sp<AMessage> &notify,
58 uint32_t flags)
Andreas Huberf9334412010-12-15 15:17:42 -080059 : mAudioSink(sink),
60 mNotify(notify),
Andreas Huberd5e56232013-03-12 11:01:43 -070061 mFlags(flags),
Andreas Huberf9334412010-12-15 15:17:42 -080062 mNumFramesWritten(0),
63 mDrainAudioQueuePending(false),
64 mDrainVideoQueuePending(false),
65 mAudioQueueGeneration(0),
66 mVideoQueueGeneration(0),
Ronghua Wua73d9e02014-10-08 15:13:29 -070067 mAudioFirstAnchorTimeMediaUs(-1),
68 mVideoAnchorTimeMediaUs(-1),
69 mVideoAnchorTimeRealUs(-1),
70 mVideoLateByUs(0ll),
Andreas Huberbc7f5b22011-01-21 10:15:23 -080071 mHasAudio(false),
72 mHasVideo(false),
Ronghua Wua73d9e02014-10-08 15:13:29 -070073 mPauseStartedTimeRealUs(-1),
74 mFlushingAudio(false),
75 mFlushingVideo(false),
Andreas Huberbc7f5b22011-01-21 10:15:23 -080076 mSyncQueues(false),
Andreas Huber714aa7b2011-09-13 08:28:38 -070077 mPaused(false),
Andy Hung09e0c362014-09-12 15:12:16 -070078 mVideoSampleReceived(false),
James Dongf57b4ea2012-07-20 13:38:36 -070079 mVideoRenderingStarted(false),
Lajos Molnarcbaffcf2013-08-14 18:30:38 -070080 mVideoRenderingStartGeneration(0),
81 mAudioRenderingStartGeneration(0),
Ronghua Wuf5b1db12014-09-09 10:11:08 -070082 mAudioOffloadPauseTimeoutGeneration(0),
83 mAudioOffloadTornDown(false) {
Lajos Molnar274084f2014-09-29 16:36:37 -070084 readProperties();
Andreas Huberf9334412010-12-15 15:17:42 -080085}
86
87NuPlayer::Renderer::~Renderer() {
Wei Jiabc2fb722014-07-08 16:37:57 -070088 if (offloadingAudio()) {
89 mAudioSink->stop();
90 mAudioSink->flush();
91 mAudioSink->close();
92 }
Andreas Huberf9334412010-12-15 15:17:42 -080093}
94
95void NuPlayer::Renderer::queueBuffer(
96 bool audio,
97 const sp<ABuffer> &buffer,
98 const sp<AMessage> &notifyConsumed) {
99 sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
100 msg->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800101 msg->setBuffer("buffer", buffer);
Andreas Huberf9334412010-12-15 15:17:42 -0800102 msg->setMessage("notifyConsumed", notifyConsumed);
103 msg->post();
104}
105
106void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
107 CHECK_NE(finalResult, (status_t)OK);
108
109 sp<AMessage> msg = new AMessage(kWhatQueueEOS, id());
110 msg->setInt32("audio", static_cast<int32_t>(audio));
111 msg->setInt32("finalResult", finalResult);
112 msg->post();
113}
114
115void NuPlayer::Renderer::flush(bool audio) {
116 {
117 Mutex::Autolock autoLock(mFlushLock);
118 if (audio) {
Wei Jia28a8a9f2014-08-18 11:29:50 -0700119 if (mFlushingAudio) {
120 return;
121 }
Andreas Huberf9334412010-12-15 15:17:42 -0800122 mFlushingAudio = true;
123 } else {
Wei Jia28a8a9f2014-08-18 11:29:50 -0700124 if (mFlushingVideo) {
125 return;
126 }
Andreas Huberf9334412010-12-15 15:17:42 -0800127 mFlushingVideo = true;
128 }
129 }
130
131 sp<AMessage> msg = new AMessage(kWhatFlush, id());
132 msg->setInt32("audio", static_cast<int32_t>(audio));
133 msg->post();
134}
135
136void NuPlayer::Renderer::signalTimeDiscontinuity() {
Wei Jiabc2fb722014-07-08 16:37:57 -0700137 Mutex::Autolock autoLock(mLock);
Andreas Huber14f76722013-01-15 09:04:18 -0800138 // CHECK(mAudioQueue.empty());
139 // CHECK(mVideoQueue.empty());
Ronghua Wua73d9e02014-10-08 15:13:29 -0700140 setAudioFirstAnchorTime(-1);
141 setVideoAnchorTime(-1, -1);
142 setVideoLateByUs(0);
Andreas Huber14f76722013-01-15 09:04:18 -0800143 mSyncQueues = false;
Andreas Huberf9334412010-12-15 15:17:42 -0800144}
145
Wei Jia28a8a9f2014-08-18 11:29:50 -0700146void NuPlayer::Renderer::signalAudioSinkChanged() {
147 (new AMessage(kWhatAudioSinkChanged, id()))->post();
148}
149
150void NuPlayer::Renderer::signalDisableOffloadAudio() {
151 (new AMessage(kWhatDisableOffloadAudio, id()))->post();
152}
153
Andreas Huberb4082222011-01-20 15:23:04 -0800154void NuPlayer::Renderer::pause() {
155 (new AMessage(kWhatPause, id()))->post();
156}
157
158void NuPlayer::Renderer::resume() {
159 (new AMessage(kWhatResume, id()))->post();
160}
161
Lajos Molnarc851b5d2014-09-18 14:14:29 -0700162void NuPlayer::Renderer::setVideoFrameRate(float fps) {
163 sp<AMessage> msg = new AMessage(kWhatSetVideoFrameRate, id());
164 msg->setFloat("frame-rate", fps);
165 msg->post();
166}
167
Ronghua Wua73d9e02014-10-08 15:13:29 -0700168status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
169 return getCurrentPosition(mediaUs, ALooper::GetNowUs());
170}
171
172status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs, int64_t nowUs) {
173 Mutex::Autolock autoLock(mTimeLock);
174 if (!mHasAudio && !mHasVideo) {
175 return NO_INIT;
176 }
177
178 int64_t positionUs = 0;
179 if (!mHasAudio) {
180 if (mVideoAnchorTimeMediaUs < 0) {
181 return NO_INIT;
182 }
183 positionUs = (nowUs - mVideoAnchorTimeRealUs) + mVideoAnchorTimeMediaUs;
184
185 if (mPauseStartedTimeRealUs != -1) {
186 positionUs -= (nowUs - mPauseStartedTimeRealUs);
187 }
188 } else {
189 if (mAudioFirstAnchorTimeMediaUs < 0) {
190 return NO_INIT;
191 }
192 positionUs = mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
193 }
194 *mediaUs = (positionUs <= 0) ? 0 : positionUs;
195 return OK;
196}
197
198void NuPlayer::Renderer::setHasMedia(bool audio) {
199 Mutex::Autolock autoLock(mTimeLock);
200 if (audio) {
201 mHasAudio = true;
202 } else {
203 mHasVideo = true;
204 }
205}
206
207void NuPlayer::Renderer::setAudioFirstAnchorTime(int64_t mediaUs) {
208 Mutex::Autolock autoLock(mTimeLock);
209 mAudioFirstAnchorTimeMediaUs = mediaUs;
210}
211
212void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs) {
213 Mutex::Autolock autoLock(mTimeLock);
214 if (mAudioFirstAnchorTimeMediaUs == -1) {
215 mAudioFirstAnchorTimeMediaUs = mediaUs;
216 }
217}
218
219void NuPlayer::Renderer::setVideoAnchorTime(int64_t mediaUs, int64_t realUs) {
220 Mutex::Autolock autoLock(mTimeLock);
221 mVideoAnchorTimeMediaUs = mediaUs;
222 mVideoAnchorTimeRealUs = realUs;
223}
224
225void NuPlayer::Renderer::setVideoLateByUs(int64_t lateUs) {
226 Mutex::Autolock autoLock(mTimeLock);
227 mVideoLateByUs = lateUs;
228}
229
230int64_t NuPlayer::Renderer::getVideoLateByUs() {
231 Mutex::Autolock autoLock(mTimeLock);
232 return mVideoLateByUs;
233}
234
235void NuPlayer::Renderer::setPauseStartedTimeRealUs(int64_t realUs) {
236 Mutex::Autolock autoLock(mTimeLock);
237 mPauseStartedTimeRealUs = realUs;
238}
239
Andreas Huberf9334412010-12-15 15:17:42 -0800240void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
241 switch (msg->what()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700242 case kWhatStopAudioSink:
243 {
244 mAudioSink->stop();
245 break;
246 }
247
Andreas Huberf9334412010-12-15 15:17:42 -0800248 case kWhatDrainAudioQueue:
249 {
250 int32_t generation;
251 CHECK(msg->findInt32("generation", &generation));
252 if (generation != mAudioQueueGeneration) {
253 break;
254 }
255
256 mDrainAudioQueuePending = false;
257
Andreas Huber078cfcf2011-09-15 12:25:04 -0700258 if (onDrainAudioQueue()) {
259 uint32_t numFramesPlayed;
260 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
261 (status_t)OK);
Andreas Huberf9334412010-12-15 15:17:42 -0800262
Andreas Huber078cfcf2011-09-15 12:25:04 -0700263 uint32_t numFramesPendingPlayout =
264 mNumFramesWritten - numFramesPlayed;
265
266 // This is how long the audio sink will have data to
267 // play back.
268 int64_t delayUs =
269 mAudioSink->msecsPerFrame()
270 * numFramesPendingPlayout * 1000ll;
271
272 // Let's give it more data after about half that time
273 // has elapsed.
Wei Jiabc2fb722014-07-08 16:37:57 -0700274 // kWhatDrainAudioQueue is used for non-offloading mode,
275 // and mLock is used only for offloading mode. Therefore,
276 // no need to acquire mLock here.
277 postDrainAudioQueue_l(delayUs / 2);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700278 }
Andreas Huberf9334412010-12-15 15:17:42 -0800279 break;
280 }
281
282 case kWhatDrainVideoQueue:
283 {
284 int32_t generation;
285 CHECK(msg->findInt32("generation", &generation));
286 if (generation != mVideoQueueGeneration) {
287 break;
288 }
289
290 mDrainVideoQueuePending = false;
291
292 onDrainVideoQueue();
293
294 postDrainVideoQueue();
295 break;
296 }
297
298 case kWhatQueueBuffer:
299 {
300 onQueueBuffer(msg);
301 break;
302 }
303
304 case kWhatQueueEOS:
305 {
306 onQueueEOS(msg);
307 break;
308 }
309
310 case kWhatFlush:
311 {
312 onFlush(msg);
313 break;
314 }
315
Andreas Huber3831a062010-12-21 10:22:33 -0800316 case kWhatAudioSinkChanged:
317 {
318 onAudioSinkChanged();
319 break;
320 }
321
Wei Jiabc2fb722014-07-08 16:37:57 -0700322 case kWhatDisableOffloadAudio:
323 {
324 onDisableOffloadAudio();
325 break;
326 }
327
Andreas Huberb4082222011-01-20 15:23:04 -0800328 case kWhatPause:
329 {
330 onPause();
331 break;
332 }
333
334 case kWhatResume:
335 {
336 onResume();
337 break;
338 }
339
Lajos Molnarc851b5d2014-09-18 14:14:29 -0700340 case kWhatSetVideoFrameRate:
341 {
342 float fps;
343 CHECK(msg->findFloat("frame-rate", &fps));
344 onSetVideoFrameRate(fps);
345 break;
346 }
347
Wei Jia3a2956d2014-07-22 16:01:33 -0700348 case kWhatAudioOffloadTearDown:
349 {
Ronghua Wu08529172014-10-02 16:55:52 -0700350 onAudioOffloadTearDown(kDueToError);
Wei Jia3a2956d2014-07-22 16:01:33 -0700351 break;
352 }
353
Ronghua Wuf5b1db12014-09-09 10:11:08 -0700354 case kWhatAudioOffloadPauseTimeout:
355 {
356 int32_t generation;
357 CHECK(msg->findInt32("generation", &generation));
358 if (generation != mAudioOffloadPauseTimeoutGeneration) {
359 break;
360 }
Ronghua Wu08529172014-10-02 16:55:52 -0700361 ALOGV("Audio Offload tear down due to pause timeout.");
362 onAudioOffloadTearDown(kDueToTimeout);
Ronghua Wuf5b1db12014-09-09 10:11:08 -0700363 break;
364 }
365
Andreas Huberf9334412010-12-15 15:17:42 -0800366 default:
367 TRESPASS();
368 break;
369 }
370}
371
Wei Jiabc2fb722014-07-08 16:37:57 -0700372void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
373 if (mDrainAudioQueuePending || mSyncQueues || mPaused
374 || offloadingAudio()) {
Andreas Huberf9334412010-12-15 15:17:42 -0800375 return;
376 }
377
378 if (mAudioQueue.empty()) {
379 return;
380 }
381
382 mDrainAudioQueuePending = true;
383 sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
384 msg->setInt32("generation", mAudioQueueGeneration);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700385 msg->post(delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800386}
387
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700388void NuPlayer::Renderer::prepareForMediaRenderingStart() {
389 mAudioRenderingStartGeneration = mAudioQueueGeneration;
390 mVideoRenderingStartGeneration = mVideoQueueGeneration;
391}
392
393void NuPlayer::Renderer::notifyIfMediaRenderingStarted() {
394 if (mVideoRenderingStartGeneration == mVideoQueueGeneration &&
395 mAudioRenderingStartGeneration == mAudioQueueGeneration) {
396 mVideoRenderingStartGeneration = -1;
397 mAudioRenderingStartGeneration = -1;
398
399 sp<AMessage> notify = mNotify->dup();
400 notify->setInt32("what", kWhatMediaRenderingStart);
401 notify->post();
402 }
403}
404
Wei Jiabc2fb722014-07-08 16:37:57 -0700405// static
406size_t NuPlayer::Renderer::AudioSinkCallback(
407 MediaPlayerBase::AudioSink * /* audioSink */,
408 void *buffer,
409 size_t size,
410 void *cookie,
411 MediaPlayerBase::AudioSink::cb_event_t event) {
412 NuPlayer::Renderer *me = (NuPlayer::Renderer *)cookie;
413
414 switch (event) {
415 case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
416 {
417 return me->fillAudioBuffer(buffer, size);
418 break;
419 }
420
421 case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
422 {
423 me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
424 break;
425 }
426
427 case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
428 {
Wei Jia3a2956d2014-07-22 16:01:33 -0700429 me->notifyAudioOffloadTearDown();
Wei Jiabc2fb722014-07-08 16:37:57 -0700430 break;
431 }
432 }
433
434 return 0;
435}
436
437size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
438 Mutex::Autolock autoLock(mLock);
439
Wei Jia73ddd212014-08-29 16:33:49 -0700440 if (!offloadingAudio() || mPaused) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700441 return 0;
442 }
443
444 bool hasEOS = false;
445
446 size_t sizeCopied = 0;
Ronghua Wu3e5efb32014-08-18 16:27:08 -0700447 bool firstEntry = true;
Wei Jiabc2fb722014-07-08 16:37:57 -0700448 while (sizeCopied < size && !mAudioQueue.empty()) {
449 QueueEntry *entry = &*mAudioQueue.begin();
450
451 if (entry->mBuffer == NULL) { // EOS
452 hasEOS = true;
453 mAudioQueue.erase(mAudioQueue.begin());
454 entry = NULL;
455 break;
456 }
457
Ronghua Wu3e5efb32014-08-18 16:27:08 -0700458 if (firstEntry && entry->mOffset == 0) {
459 firstEntry = false;
Wei Jiabc2fb722014-07-08 16:37:57 -0700460 int64_t mediaTimeUs;
461 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
462 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
Ronghua Wua73d9e02014-10-08 15:13:29 -0700463 setAudioFirstAnchorTimeIfNeeded(mediaTimeUs);
Wei Jiabc2fb722014-07-08 16:37:57 -0700464 }
465
466 size_t copy = entry->mBuffer->size() - entry->mOffset;
467 size_t sizeRemaining = size - sizeCopied;
468 if (copy > sizeRemaining) {
469 copy = sizeRemaining;
470 }
471
472 memcpy((char *)buffer + sizeCopied,
473 entry->mBuffer->data() + entry->mOffset,
474 copy);
475
476 entry->mOffset += copy;
477 if (entry->mOffset == entry->mBuffer->size()) {
478 entry->mNotifyConsumed->post();
479 mAudioQueue.erase(mAudioQueue.begin());
480 entry = NULL;
481 }
482 sizeCopied += copy;
483 notifyIfMediaRenderingStarted();
484 }
485
Wei Jiabc2fb722014-07-08 16:37:57 -0700486 if (hasEOS) {
487 (new AMessage(kWhatStopAudioSink, id()))->post();
488 }
489
490 return sizeCopied;
491}
492
Andreas Huber078cfcf2011-09-15 12:25:04 -0700493bool NuPlayer::Renderer::onDrainAudioQueue() {
494 uint32_t numFramesPlayed;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700495 if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
496 return false;
497 }
Andreas Huberc92fd242011-08-16 13:48:44 -0700498
Andreas Huber078cfcf2011-09-15 12:25:04 -0700499 ssize_t numFramesAvailableToWrite =
500 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
501
502#if 0
503 if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
Steve Blockdf64d152012-01-04 20:05:49 +0000504 ALOGI("audio sink underrun");
Andreas Huber078cfcf2011-09-15 12:25:04 -0700505 } else {
Steve Block3856b092011-10-20 11:56:00 +0100506 ALOGV("audio queue has %d frames left to play",
Andreas Huber078cfcf2011-09-15 12:25:04 -0700507 mAudioSink->frameCount() - numFramesAvailableToWrite);
508 }
509#endif
510
511 size_t numBytesAvailableToWrite =
512 numFramesAvailableToWrite * mAudioSink->frameSize();
513
514 while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
Andreas Huberc92fd242011-08-16 13:48:44 -0700515 QueueEntry *entry = &*mAudioQueue.begin();
516
517 if (entry->mBuffer == NULL) {
518 // EOS
Ronghua Wu5095d702014-08-27 12:05:48 -0700519 int64_t postEOSDelayUs = 0;
520 if (mAudioSink->needsTrailingPadding()) {
Lajos Molnar06ad1522014-08-28 07:27:44 -0700521 postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
Ronghua Wu5095d702014-08-27 12:05:48 -0700522 }
523 notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
Andreas Huberc92fd242011-08-16 13:48:44 -0700524
525 mAudioQueue.erase(mAudioQueue.begin());
526 entry = NULL;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700527 return false;
Eric Laurent9b7d9502011-03-21 11:49:00 -0700528 }
529
Andreas Huberf9334412010-12-15 15:17:42 -0800530 if (entry->mOffset == 0) {
531 int64_t mediaTimeUs;
532 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
Steve Block3856b092011-10-20 11:56:00 +0100533 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
Andreas Huberf9334412010-12-15 15:17:42 -0800534
Ronghua Wua73d9e02014-10-08 15:13:29 -0700535 setAudioFirstAnchorTimeIfNeeded(mediaTimeUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800536 }
537
538 size_t copy = entry->mBuffer->size() - entry->mOffset;
539 if (copy > numBytesAvailableToWrite) {
540 copy = numBytesAvailableToWrite;
541 }
542
Andy Hunga31335a2014-08-20 17:37:59 -0700543 ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy);
544 if (written < 0) {
545 // An error in AudioSink write is fatal here.
546 LOG_ALWAYS_FATAL("AudioSink write error(%zd) when writing %zu bytes", written, copy);
547 }
Andreas Huberf9334412010-12-15 15:17:42 -0800548
Andy Hunga31335a2014-08-20 17:37:59 -0700549 entry->mOffset += written;
Andreas Huberf9334412010-12-15 15:17:42 -0800550 if (entry->mOffset == entry->mBuffer->size()) {
551 entry->mNotifyConsumed->post();
552 mAudioQueue.erase(mAudioQueue.begin());
Eric Laurent9b7d9502011-03-21 11:49:00 -0700553
Andreas Huberf9334412010-12-15 15:17:42 -0800554 entry = NULL;
555 }
556
Andy Hunga31335a2014-08-20 17:37:59 -0700557 numBytesAvailableToWrite -= written;
558 size_t copiedFrames = written / mAudioSink->frameSize();
Andreas Huber078cfcf2011-09-15 12:25:04 -0700559 mNumFramesWritten += copiedFrames;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700560
561 notifyIfMediaRenderingStarted();
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800562
Andy Hunga31335a2014-08-20 17:37:59 -0700563 if (written != (ssize_t)copy) {
564 // A short count was received from AudioSink::write()
565 //
566 // AudioSink write should block until exactly the number of bytes are delivered.
567 // But it may return with a short count (without an error) when:
568 //
569 // 1) Size to be copied is not a multiple of the frame size. We consider this fatal.
570 // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
571
572 // (Case 1)
573 // Must be a multiple of the frame size. If it is not a multiple of a frame size, it
574 // needs to fail, as we should not carry over fractional frames between calls.
575 CHECK_EQ(copy % mAudioSink->frameSize(), 0);
576
577 // (Case 2)
578 // Return early to the caller.
579 // Beware of calling immediately again as this may busy-loop if you are not careful.
580 ALOGW("AudioSink write short frame count %zd < %zu", written, copy);
581 break;
582 }
583 }
Andreas Huber078cfcf2011-09-15 12:25:04 -0700584 return !mAudioQueue.empty();
Andreas Huberf9334412010-12-15 15:17:42 -0800585}
586
Lajos Molnar06ad1522014-08-28 07:27:44 -0700587int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
588 int64_t writtenAudioDurationUs =
589 mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame();
590 return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
Ronghua Wu5095d702014-08-27 12:05:48 -0700591}
592
Ronghua Wua73d9e02014-10-08 15:13:29 -0700593int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
594 int64_t currentPositionUs;
595 if (getCurrentPosition(&currentPositionUs, nowUs) != OK) {
596 currentPositionUs = 0;
597 }
598 return (mediaTimeUs - currentPositionUs) + nowUs;
599}
600
Andreas Huberf9334412010-12-15 15:17:42 -0800601void NuPlayer::Renderer::postDrainVideoQueue() {
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700602 if (mDrainVideoQueuePending
603 || mSyncQueues
604 || (mPaused && mVideoSampleReceived)) {
Andreas Huberf9334412010-12-15 15:17:42 -0800605 return;
606 }
607
608 if (mVideoQueue.empty()) {
609 return;
610 }
611
612 QueueEntry &entry = *mVideoQueue.begin();
613
614 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
615 msg->setInt32("generation", mVideoQueueGeneration);
616
Andreas Huberf9334412010-12-15 15:17:42 -0800617 if (entry.mBuffer == NULL) {
618 // EOS doesn't carry a timestamp.
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700619 msg->post();
620 mDrainVideoQueuePending = true;
621 return;
622 }
623
624 int64_t delayUs;
625 int64_t nowUs = ALooper::GetNowUs();
626 int64_t realTimeUs;
627 if (mFlags & FLAG_REAL_TIME) {
Andreas Huberd5e56232013-03-12 11:01:43 -0700628 int64_t mediaTimeUs;
629 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700630 realTimeUs = mediaTimeUs;
Andreas Huberf9334412010-12-15 15:17:42 -0800631 } else {
632 int64_t mediaTimeUs;
633 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
634
Ronghua Wua73d9e02014-10-08 15:13:29 -0700635 if (mVideoAnchorTimeMediaUs < 0) {
636 setVideoAnchorTime(mediaTimeUs, nowUs);
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700637 realTimeUs = nowUs;
Andreas Huberf9334412010-12-15 15:17:42 -0800638 } else {
Ronghua Wua73d9e02014-10-08 15:13:29 -0700639 realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800640 }
641 }
642
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700643 realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
644 int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
645
646 delayUs = realTimeUs - nowUs;
647
Lajos Molnar09524832014-07-17 14:29:51 -0700648 ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700649 // post 2 display refreshes before rendering is due
Lajos Molnar274084f2014-09-29 16:36:37 -0700650 // FIXME currently this increases power consumption, so unless frame-accurate
651 // AV sync is requested, post closer to required render time (at 0.63 vsyncs)
652 if (!sFrameAccurateAVsync) {
653 twoVsyncsUs >>= 4;
654 }
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700655 msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
Andreas Huberf9334412010-12-15 15:17:42 -0800656
657 mDrainVideoQueuePending = true;
658}
659
660void NuPlayer::Renderer::onDrainVideoQueue() {
661 if (mVideoQueue.empty()) {
662 return;
663 }
664
665 QueueEntry *entry = &*mVideoQueue.begin();
666
667 if (entry->mBuffer == NULL) {
668 // EOS
669
Andreas Huberc92fd242011-08-16 13:48:44 -0700670 notifyEOS(false /* audio */, entry->mFinalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800671
672 mVideoQueue.erase(mVideoQueue.begin());
673 entry = NULL;
Andreas Huber3fe62152011-09-16 15:09:22 -0700674
Ronghua Wua73d9e02014-10-08 15:13:29 -0700675 setVideoLateByUs(0);
Andreas Huberf9334412010-12-15 15:17:42 -0800676 return;
677 }
678
Ronghua Wua73d9e02014-10-08 15:13:29 -0700679 int64_t nowUs = -1;
Andreas Huberd5e56232013-03-12 11:01:43 -0700680 int64_t realTimeUs;
681 if (mFlags & FLAG_REAL_TIME) {
682 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
683 } else {
684 int64_t mediaTimeUs;
685 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
Andreas Huberf9334412010-12-15 15:17:42 -0800686
Ronghua Wua73d9e02014-10-08 15:13:29 -0700687 nowUs = ALooper::GetNowUs();
688 realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
Andreas Huberd5e56232013-03-12 11:01:43 -0700689 }
690
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700691 bool tooLate = false;
Andreas Huber3fe62152011-09-16 15:09:22 -0700692
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700693 if (!mPaused) {
Ronghua Wua73d9e02014-10-08 15:13:29 -0700694 if (nowUs == -1) {
695 nowUs = ALooper::GetNowUs();
696 }
697 setVideoLateByUs(nowUs - realTimeUs);
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700698 tooLate = (mVideoLateByUs > 40000);
699
700 if (tooLate) {
701 ALOGV("video late by %lld us (%.2f secs)",
702 mVideoLateByUs, mVideoLateByUs / 1E6);
703 } else {
704 ALOGV("rendering video at media time %.2f secs",
705 (mFlags & FLAG_REAL_TIME ? realTimeUs :
Ronghua Wua73d9e02014-10-08 15:13:29 -0700706 (realTimeUs + mVideoAnchorTimeMediaUs - mVideoAnchorTimeRealUs)) / 1E6);
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700707 }
Andreas Huber078cfcf2011-09-15 12:25:04 -0700708 } else {
Ronghua Wua73d9e02014-10-08 15:13:29 -0700709 setVideoLateByUs(0);
710 if (!mVideoSampleReceived) {
711 // This will ensure that the first frame after a flush won't be used as anchor
712 // when renderer is in paused state, because resume can happen any time after seek.
713 setVideoAnchorTime(-1, -1);
Wei Jia49966ff2014-10-08 18:44:45 -0700714 }
Andreas Huber078cfcf2011-09-15 12:25:04 -0700715 }
Andreas Huberf9334412010-12-15 15:17:42 -0800716
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700717 entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000ll);
Glenn Kasten683525b2011-11-04 18:05:35 -0700718 entry->mNotifyConsumed->setInt32("render", !tooLate);
Andreas Huberf9334412010-12-15 15:17:42 -0800719 entry->mNotifyConsumed->post();
720 mVideoQueue.erase(mVideoQueue.begin());
721 entry = NULL;
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800722
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700723 mVideoSampleReceived = true;
James Dongf57b4ea2012-07-20 13:38:36 -0700724
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700725 if (!mPaused) {
726 if (!mVideoRenderingStarted) {
727 mVideoRenderingStarted = true;
728 notifyVideoRenderingStart();
729 }
730 notifyIfMediaRenderingStarted();
731 }
Andreas Huberf9334412010-12-15 15:17:42 -0800732}
733
James Dongf57b4ea2012-07-20 13:38:36 -0700734void NuPlayer::Renderer::notifyVideoRenderingStart() {
735 sp<AMessage> notify = mNotify->dup();
736 notify->setInt32("what", kWhatVideoRenderingStart);
737 notify->post();
738}
739
Ronghua Wu5095d702014-08-27 12:05:48 -0700740void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
Andreas Huberf9334412010-12-15 15:17:42 -0800741 sp<AMessage> notify = mNotify->dup();
742 notify->setInt32("what", kWhatEOS);
743 notify->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huberc92fd242011-08-16 13:48:44 -0700744 notify->setInt32("finalResult", finalResult);
Ronghua Wu5095d702014-08-27 12:05:48 -0700745 notify->post(delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800746}
747
Wei Jia3a2956d2014-07-22 16:01:33 -0700748void NuPlayer::Renderer::notifyAudioOffloadTearDown() {
749 (new AMessage(kWhatAudioOffloadTearDown, id()))->post();
750}
751
Andreas Huberf9334412010-12-15 15:17:42 -0800752void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
753 int32_t audio;
754 CHECK(msg->findInt32("audio", &audio));
755
Ronghua Wua73d9e02014-10-08 15:13:29 -0700756 setHasMedia(audio);
757
758 if (mHasVideo) {
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700759 if (mVideoScheduler == NULL) {
760 mVideoScheduler = new VideoFrameScheduler();
761 mVideoScheduler->init();
762 }
Andreas Huberbc7f5b22011-01-21 10:15:23 -0800763 }
764
Andreas Huberf9334412010-12-15 15:17:42 -0800765 if (dropBufferWhileFlushing(audio, msg)) {
766 return;
767 }
768
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800769 sp<ABuffer> buffer;
770 CHECK(msg->findBuffer("buffer", &buffer));
Andreas Huberf9334412010-12-15 15:17:42 -0800771
772 sp<AMessage> notifyConsumed;
773 CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
774
775 QueueEntry entry;
776 entry.mBuffer = buffer;
777 entry.mNotifyConsumed = notifyConsumed;
778 entry.mOffset = 0;
779 entry.mFinalResult = OK;
780
781 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700782 Mutex::Autolock autoLock(mLock);
Andreas Huberf9334412010-12-15 15:17:42 -0800783 mAudioQueue.push_back(entry);
Wei Jiabc2fb722014-07-08 16:37:57 -0700784 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800785 } else {
786 mVideoQueue.push_back(entry);
787 postDrainVideoQueue();
788 }
789
Wei Jiabc2fb722014-07-08 16:37:57 -0700790 Mutex::Autolock autoLock(mLock);
Andreas Hubercb67cd12011-08-26 16:02:19 -0700791 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
792 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800793 }
Andreas Hubercb67cd12011-08-26 16:02:19 -0700794
795 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
796 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
797
798 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
799 // EOS signalled on either queue.
Wei Jiabc2fb722014-07-08 16:37:57 -0700800 syncQueuesDone_l();
Andreas Hubercb67cd12011-08-26 16:02:19 -0700801 return;
802 }
803
804 int64_t firstAudioTimeUs;
805 int64_t firstVideoTimeUs;
806 CHECK(firstAudioBuffer->meta()
807 ->findInt64("timeUs", &firstAudioTimeUs));
808 CHECK(firstVideoBuffer->meta()
809 ->findInt64("timeUs", &firstVideoTimeUs));
810
811 int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
812
Steve Block3856b092011-10-20 11:56:00 +0100813 ALOGV("queueDiff = %.2f secs", diff / 1E6);
Andreas Hubercb67cd12011-08-26 16:02:19 -0700814
815 if (diff > 100000ll) {
816 // Audio data starts More than 0.1 secs before video.
817 // Drop some audio.
818
819 (*mAudioQueue.begin()).mNotifyConsumed->post();
820 mAudioQueue.erase(mAudioQueue.begin());
821 return;
822 }
823
Wei Jiabc2fb722014-07-08 16:37:57 -0700824 syncQueuesDone_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800825}
826
Wei Jiabc2fb722014-07-08 16:37:57 -0700827void NuPlayer::Renderer::syncQueuesDone_l() {
Andreas Huberf9334412010-12-15 15:17:42 -0800828 if (!mSyncQueues) {
829 return;
830 }
831
832 mSyncQueues = false;
833
834 if (!mAudioQueue.empty()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700835 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800836 }
837
838 if (!mVideoQueue.empty()) {
839 postDrainVideoQueue();
840 }
841}
842
843void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {
844 int32_t audio;
845 CHECK(msg->findInt32("audio", &audio));
846
847 if (dropBufferWhileFlushing(audio, msg)) {
848 return;
849 }
850
851 int32_t finalResult;
852 CHECK(msg->findInt32("finalResult", &finalResult));
853
854 QueueEntry entry;
855 entry.mOffset = 0;
856 entry.mFinalResult = finalResult;
857
858 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700859 Mutex::Autolock autoLock(mLock);
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100860 if (mAudioQueue.empty() && mSyncQueues) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700861 syncQueuesDone_l();
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100862 }
Andreas Huberf9334412010-12-15 15:17:42 -0800863 mAudioQueue.push_back(entry);
Wei Jiabc2fb722014-07-08 16:37:57 -0700864 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800865 } else {
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100866 if (mVideoQueue.empty() && mSyncQueues) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700867 Mutex::Autolock autoLock(mLock);
868 syncQueuesDone_l();
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100869 }
Andreas Huberf9334412010-12-15 15:17:42 -0800870 mVideoQueue.push_back(entry);
871 postDrainVideoQueue();
872 }
873}
874
875void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
876 int32_t audio;
877 CHECK(msg->findInt32("audio", &audio));
878
Wei Jia28a8a9f2014-08-18 11:29:50 -0700879 {
880 Mutex::Autolock autoLock(mFlushLock);
881 if (audio) {
882 mFlushingAudio = false;
883 } else {
884 mFlushingVideo = false;
885 }
886 }
887
Andreas Huberf9334412010-12-15 15:17:42 -0800888 // If we're currently syncing the queues, i.e. dropping audio while
889 // aligning the first audio/video buffer times and only one of the
890 // two queues has data, we may starve that queue by not requesting
891 // more buffers from the decoder. If the other source then encounters
892 // a discontinuity that leads to flushing, we'll never find the
893 // corresponding discontinuity on the other queue.
894 // Therefore we'll stop syncing the queues if at least one of them
895 // is flushed.
Wei Jiabc2fb722014-07-08 16:37:57 -0700896 {
897 Mutex::Autolock autoLock(mLock);
898 syncQueuesDone_l();
Ronghua Wua73d9e02014-10-08 15:13:29 -0700899 setPauseStartedTimeRealUs(-1);
Wei Jiabc2fb722014-07-08 16:37:57 -0700900 }
Andreas Huberf9334412010-12-15 15:17:42 -0800901
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700902 ALOGV("flushing %s", audio ? "audio" : "video");
Andreas Huberf9334412010-12-15 15:17:42 -0800903 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700904 {
905 Mutex::Autolock autoLock(mLock);
906 flushQueue(&mAudioQueue);
Wei Jia28a8a9f2014-08-18 11:29:50 -0700907
908 ++mAudioQueueGeneration;
909 prepareForMediaRenderingStart();
910
911 if (offloadingAudio()) {
Ronghua Wua73d9e02014-10-08 15:13:29 -0700912 setAudioFirstAnchorTime(-1);
Wei Jia28a8a9f2014-08-18 11:29:50 -0700913 }
Wei Jiabc2fb722014-07-08 16:37:57 -0700914 }
Andreas Huberf9334412010-12-15 15:17:42 -0800915
Andreas Huberf9334412010-12-15 15:17:42 -0800916 mDrainAudioQueuePending = false;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700917
Wei Jiabc2fb722014-07-08 16:37:57 -0700918 if (offloadingAudio()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700919 mAudioSink->pause();
920 mAudioSink->flush();
921 mAudioSink->start();
922 }
Andreas Huberf9334412010-12-15 15:17:42 -0800923 } else {
924 flushQueue(&mVideoQueue);
925
Andreas Huberf9334412010-12-15 15:17:42 -0800926 mDrainVideoQueuePending = false;
927 ++mVideoQueueGeneration;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700928
Lajos Molnarc851b5d2014-09-18 14:14:29 -0700929 if (mVideoScheduler != NULL) {
930 mVideoScheduler->restart();
931 }
932
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700933 prepareForMediaRenderingStart();
Andreas Huberf9334412010-12-15 15:17:42 -0800934 }
935
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700936 mVideoSampleReceived = false;
Andreas Huberf9334412010-12-15 15:17:42 -0800937 notifyFlushComplete(audio);
938}
939
940void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) {
941 while (!queue->empty()) {
942 QueueEntry *entry = &*queue->begin();
943
944 if (entry->mBuffer != NULL) {
945 entry->mNotifyConsumed->post();
946 }
947
948 queue->erase(queue->begin());
949 entry = NULL;
950 }
951}
952
953void NuPlayer::Renderer::notifyFlushComplete(bool audio) {
954 sp<AMessage> notify = mNotify->dup();
955 notify->setInt32("what", kWhatFlushComplete);
956 notify->setInt32("audio", static_cast<int32_t>(audio));
957 notify->post();
958}
959
960bool NuPlayer::Renderer::dropBufferWhileFlushing(
961 bool audio, const sp<AMessage> &msg) {
962 bool flushing = false;
963
964 {
965 Mutex::Autolock autoLock(mFlushLock);
966 if (audio) {
967 flushing = mFlushingAudio;
968 } else {
969 flushing = mFlushingVideo;
970 }
971 }
972
973 if (!flushing) {
974 return false;
975 }
976
977 sp<AMessage> notifyConsumed;
978 if (msg->findMessage("notifyConsumed", &notifyConsumed)) {
979 notifyConsumed->post();
980 }
981
982 return true;
983}
984
Andreas Huber3831a062010-12-21 10:22:33 -0800985void NuPlayer::Renderer::onAudioSinkChanged() {
Wei Jiabc2fb722014-07-08 16:37:57 -0700986 if (offloadingAudio()) {
987 return;
988 }
Andreas Huber3831a062010-12-21 10:22:33 -0800989 CHECK(!mDrainAudioQueuePending);
990 mNumFramesWritten = 0;
Marco Nelissen4110c102012-03-29 09:31:28 -0700991 uint32_t written;
992 if (mAudioSink->getFramesWritten(&written) == OK) {
993 mNumFramesWritten = written;
994 }
Andreas Huber3831a062010-12-21 10:22:33 -0800995}
996
Wei Jiabc2fb722014-07-08 16:37:57 -0700997void NuPlayer::Renderer::onDisableOffloadAudio() {
998 Mutex::Autolock autoLock(mLock);
999 mFlags &= ~FLAG_OFFLOAD_AUDIO;
Wei Jia3a2956d2014-07-22 16:01:33 -07001000 ++mAudioQueueGeneration;
Wei Jiabc2fb722014-07-08 16:37:57 -07001001}
1002
Andreas Huberb4082222011-01-20 15:23:04 -08001003void NuPlayer::Renderer::onPause() {
Rachad8592dbb2014-09-09 13:10:28 -07001004 if (mPaused) {
1005 ALOGW("Renderer::onPause() called while already paused!");
1006 return;
1007 }
Wei Jia28a8a9f2014-08-18 11:29:50 -07001008 {
1009 Mutex::Autolock autoLock(mLock);
1010 ++mAudioQueueGeneration;
1011 ++mVideoQueueGeneration;
1012 prepareForMediaRenderingStart();
Wei Jia73ddd212014-08-29 16:33:49 -07001013 mPaused = true;
Ronghua Wua73d9e02014-10-08 15:13:29 -07001014 setPauseStartedTimeRealUs(ALooper::GetNowUs());
Wei Jia28a8a9f2014-08-18 11:29:50 -07001015 }
1016
Andreas Huberb4082222011-01-20 15:23:04 -08001017 mDrainAudioQueuePending = false;
Andreas Huberb4082222011-01-20 15:23:04 -08001018 mDrainVideoQueuePending = false;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -07001019
Andreas Huberb4082222011-01-20 15:23:04 -08001020 if (mHasAudio) {
1021 mAudioSink->pause();
Ronghua Wuf5b1db12014-09-09 10:11:08 -07001022 startAudioOffloadPauseTimeout();
Andreas Huberb4082222011-01-20 15:23:04 -08001023 }
1024
Andreas Huberea9d51b2011-11-30 09:53:40 -08001025 ALOGV("now paused audio queue has %d entries, video has %d entries",
1026 mAudioQueue.size(), mVideoQueue.size());
Andreas Huberb4082222011-01-20 15:23:04 -08001027}
1028
1029void NuPlayer::Renderer::onResume() {
Lajos Molnar274084f2014-09-29 16:36:37 -07001030 readProperties();
1031
Andreas Huberb58ce9f2011-11-28 16:27:35 -08001032 if (!mPaused) {
1033 return;
1034 }
Andreas Huberb4082222011-01-20 15:23:04 -08001035
1036 if (mHasAudio) {
Ronghua Wuf5b1db12014-09-09 10:11:08 -07001037 cancelAudioOffloadPauseTimeout();
Andreas Huberb4082222011-01-20 15:23:04 -08001038 mAudioSink->start();
1039 }
1040
Wei Jia73ddd212014-08-29 16:33:49 -07001041 Mutex::Autolock autoLock(mLock);
Andreas Huberb4082222011-01-20 15:23:04 -08001042 mPaused = false;
Ronghua Wua73d9e02014-10-08 15:13:29 -07001043 if (mPauseStartedTimeRealUs != -1) {
1044 int64_t newAnchorRealUs =
1045 mVideoAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs;
1046 setVideoAnchorTime(mVideoAnchorTimeMediaUs, newAnchorRealUs);
1047 setPauseStartedTimeRealUs(-1);
Wei Jia49966ff2014-10-08 18:44:45 -07001048 }
Andreas Huberb4082222011-01-20 15:23:04 -08001049
1050 if (!mAudioQueue.empty()) {
Wei Jiabc2fb722014-07-08 16:37:57 -07001051 postDrainAudioQueue_l();
Andreas Huberb4082222011-01-20 15:23:04 -08001052 }
1053
1054 if (!mVideoQueue.empty()) {
1055 postDrainVideoQueue();
1056 }
1057}
1058
Lajos Molnarc851b5d2014-09-18 14:14:29 -07001059void NuPlayer::Renderer::onSetVideoFrameRate(float fps) {
1060 if (mVideoScheduler == NULL) {
1061 mVideoScheduler = new VideoFrameScheduler();
1062 }
1063 mVideoScheduler->init(fps);
1064}
1065
Andy Hung09e0c362014-09-12 15:12:16 -07001066// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs()
1067// as it acquires locks and may query the audio driver.
1068//
Andy Hung09e0c362014-09-12 15:12:16 -07001069// Some calls could conceivably retrieve extrapolated data instead of
1070// accessing getTimestamp() or getPosition() every time a data buffer with
1071// a media time is received.
1072//
Lajos Molnar06ad1522014-08-28 07:27:44 -07001073int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
Wei Jia3a2956d2014-07-22 16:01:33 -07001074 uint32_t numFramesPlayed;
Lajos Molnar06ad1522014-08-28 07:27:44 -07001075 int64_t numFramesPlayedAt;
1076 AudioTimestamp ts;
Andy Hung09e0c362014-09-12 15:12:16 -07001077 static const int64_t kStaleTimestamp100ms = 100000;
1078
Lajos Molnar06ad1522014-08-28 07:27:44 -07001079 status_t res = mAudioSink->getTimestamp(ts);
Andy Hung09e0c362014-09-12 15:12:16 -07001080 if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
Lajos Molnar06ad1522014-08-28 07:27:44 -07001081 numFramesPlayed = ts.mPosition;
1082 numFramesPlayedAt =
1083 ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
Andy Hung09e0c362014-09-12 15:12:16 -07001084 const int64_t timestampAge = nowUs - numFramesPlayedAt;
1085 if (timestampAge > kStaleTimestamp100ms) {
1086 // This is an audio FIXME.
1087 // getTimestamp returns a timestamp which may come from audio mixing threads.
1088 // After pausing, the MixerThread may go idle, thus the mTime estimate may
1089 // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
1090 // the max latency should be about 25ms with an average around 12ms (to be verified).
1091 // For safety we use 100ms.
Andy Hung2abde2c2014-09-30 14:40:32 -07001092 ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
Andy Hung09e0c362014-09-12 15:12:16 -07001093 (long long)nowUs, (long long)numFramesPlayedAt);
1094 numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
1095 }
1096 //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
1097 } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
1098 numFramesPlayed = 0;
1099 numFramesPlayedAt = nowUs;
1100 //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
1101 // numFramesPlayed, (long long)numFramesPlayedAt);
1102 } else { // case 3: transitory at new track or audio fast tracks.
Lajos Molnar06ad1522014-08-28 07:27:44 -07001103 res = mAudioSink->getPosition(&numFramesPlayed);
1104 CHECK_EQ(res, (status_t)OK);
1105 numFramesPlayedAt = nowUs;
1106 numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
Andy Hung09e0c362014-09-12 15:12:16 -07001107 //ALOGD("getPosition: %d %lld", numFramesPlayed, numFramesPlayedAt);
Lajos Molnar06ad1522014-08-28 07:27:44 -07001108 }
Andy Hung09e0c362014-09-12 15:12:16 -07001109
1110 // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
1111 //CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
1112 int64_t durationUs = (int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame()
Lajos Molnar06ad1522014-08-28 07:27:44 -07001113 + nowUs - numFramesPlayedAt;
Andy Hung09e0c362014-09-12 15:12:16 -07001114 if (durationUs < 0) {
1115 // Occurs when numFramesPlayed position is very small and the following:
1116 // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
1117 // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
1118 // (2) In case 3, using getPosition and adding mAudioSink->latency() to
1119 // numFramesPlayedAt, by a time amount greater than numFramesPlayed.
1120 //
1121 // Both of these are transitory conditions.
Andy Hung2abde2c2014-09-30 14:40:32 -07001122 ALOGV("getPlayedOutAudioDurationUs: negative duration %lld set to zero", (long long)durationUs);
Andy Hung09e0c362014-09-12 15:12:16 -07001123 durationUs = 0;
1124 }
1125 ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
1126 (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
1127 return durationUs;
Lajos Molnar06ad1522014-08-28 07:27:44 -07001128}
Wei Jia3a2956d2014-07-22 16:01:33 -07001129
Ronghua Wu08529172014-10-02 16:55:52 -07001130void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reason) {
Ronghua Wuf5b1db12014-09-09 10:11:08 -07001131 if (mAudioOffloadTornDown) {
1132 return;
1133 }
1134 mAudioOffloadTornDown = true;
1135
Ronghua Wua73d9e02014-10-08 15:13:29 -07001136 int64_t currentPositionUs;
1137 if (getCurrentPosition(&currentPositionUs) != OK) {
1138 currentPositionUs = 0;
Wei Jia28a8a9f2014-08-18 11:29:50 -07001139 }
Lajos Molnar06ad1522014-08-28 07:27:44 -07001140
Wei Jia3a2956d2014-07-22 16:01:33 -07001141 mAudioSink->stop();
1142 mAudioSink->flush();
1143
1144 sp<AMessage> notify = mNotify->dup();
1145 notify->setInt32("what", kWhatAudioOffloadTearDown);
1146 notify->setInt64("positionUs", currentPositionUs);
Ronghua Wu08529172014-10-02 16:55:52 -07001147 notify->setInt32("reason", reason);
Wei Jia3a2956d2014-07-22 16:01:33 -07001148 notify->post();
1149}
1150
Ronghua Wuf5b1db12014-09-09 10:11:08 -07001151void NuPlayer::Renderer::startAudioOffloadPauseTimeout() {
1152 if (offloadingAudio()) {
1153 sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, id());
1154 msg->setInt32("generation", mAudioOffloadPauseTimeoutGeneration);
1155 msg->post(kOffloadPauseMaxUs);
1156 }
1157}
1158
1159void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() {
1160 if (offloadingAudio()) {
1161 ++mAudioOffloadPauseTimeoutGeneration;
1162 }
1163}
1164
Andreas Huberf9334412010-12-15 15:17:42 -08001165} // namespace android
1166