blob: 4ffcea6e3b6e47cf6d1d004da2603e2b17251268 [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
23#include <media/stagefright/foundation/ABuffer.h>
24#include <media/stagefright/foundation/ADebug.h>
Andreas Huber5bc087c2010-12-23 10:27:40 -080025#include <media/stagefright/foundation/AMessage.h>
Wei Jiabc2fb722014-07-08 16:37:57 -070026#include <media/stagefright/MediaErrors.h>
27#include <media/stagefright/MetaData.h>
Andreas Huberf9334412010-12-15 15:17:42 -080028
Lajos Molnar09524832014-07-17 14:29:51 -070029#include <inttypes.h>
30
Andreas Huberf9334412010-12-15 15:17:42 -080031namespace android {
32
Ronghua Wuf5b1db12014-09-09 10:11:08 -070033// Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink
34// is closed to allow the audio DSP to power down.
35static const int64_t kOffloadPauseMaxUs = 60000000ll;
36
Andreas Huber714aa7b2011-09-13 08:28:38 -070037// static
38const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
39
Andreas Huberf9334412010-12-15 15:17:42 -080040NuPlayer::Renderer::Renderer(
41 const sp<MediaPlayerBase::AudioSink> &sink,
Andreas Huberd5e56232013-03-12 11:01:43 -070042 const sp<AMessage> &notify,
43 uint32_t flags)
Andreas Huberf9334412010-12-15 15:17:42 -080044 : mAudioSink(sink),
45 mNotify(notify),
Andreas Huberd5e56232013-03-12 11:01:43 -070046 mFlags(flags),
Andreas Huberf9334412010-12-15 15:17:42 -080047 mNumFramesWritten(0),
48 mDrainAudioQueuePending(false),
49 mDrainVideoQueuePending(false),
50 mAudioQueueGeneration(0),
51 mVideoQueueGeneration(0),
Andy Hung09e0c362014-09-12 15:12:16 -070052 mFirstAnchorTimeMediaUs(-1),
Andreas Huberf9334412010-12-15 15:17:42 -080053 mAnchorTimeMediaUs(-1),
54 mAnchorTimeRealUs(-1),
55 mFlushingAudio(false),
56 mFlushingVideo(false),
Andreas Huberbc7f5b22011-01-21 10:15:23 -080057 mHasAudio(false),
58 mHasVideo(false),
59 mSyncQueues(false),
Andreas Huber714aa7b2011-09-13 08:28:38 -070060 mPaused(false),
Andy Hung09e0c362014-09-12 15:12:16 -070061 mVideoSampleReceived(false),
James Dongf57b4ea2012-07-20 13:38:36 -070062 mVideoRenderingStarted(false),
Lajos Molnarcbaffcf2013-08-14 18:30:38 -070063 mVideoRenderingStartGeneration(0),
64 mAudioRenderingStartGeneration(0),
Andreas Huber3fe62152011-09-16 15:09:22 -070065 mLastPositionUpdateUs(-1ll),
Ronghua Wuf5b1db12014-09-09 10:11:08 -070066 mVideoLateByUs(0ll),
67 mAudioOffloadPauseTimeoutGeneration(0),
68 mAudioOffloadTornDown(false) {
Andreas Huberf9334412010-12-15 15:17:42 -080069}
70
71NuPlayer::Renderer::~Renderer() {
Wei Jiabc2fb722014-07-08 16:37:57 -070072 if (offloadingAudio()) {
73 mAudioSink->stop();
74 mAudioSink->flush();
75 mAudioSink->close();
76 }
Andreas Huberf9334412010-12-15 15:17:42 -080077}
78
79void NuPlayer::Renderer::queueBuffer(
80 bool audio,
81 const sp<ABuffer> &buffer,
82 const sp<AMessage> &notifyConsumed) {
83 sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
84 msg->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huber2d8bedd2012-02-21 14:38:23 -080085 msg->setBuffer("buffer", buffer);
Andreas Huberf9334412010-12-15 15:17:42 -080086 msg->setMessage("notifyConsumed", notifyConsumed);
87 msg->post();
88}
89
90void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
91 CHECK_NE(finalResult, (status_t)OK);
92
93 sp<AMessage> msg = new AMessage(kWhatQueueEOS, id());
94 msg->setInt32("audio", static_cast<int32_t>(audio));
95 msg->setInt32("finalResult", finalResult);
96 msg->post();
97}
98
99void NuPlayer::Renderer::flush(bool audio) {
100 {
101 Mutex::Autolock autoLock(mFlushLock);
102 if (audio) {
Wei Jia28a8a9f2014-08-18 11:29:50 -0700103 if (mFlushingAudio) {
104 return;
105 }
Andreas Huberf9334412010-12-15 15:17:42 -0800106 mFlushingAudio = true;
107 } else {
Wei Jia28a8a9f2014-08-18 11:29:50 -0700108 if (mFlushingVideo) {
109 return;
110 }
Andreas Huberf9334412010-12-15 15:17:42 -0800111 mFlushingVideo = true;
112 }
113 }
114
115 sp<AMessage> msg = new AMessage(kWhatFlush, id());
116 msg->setInt32("audio", static_cast<int32_t>(audio));
117 msg->post();
118}
119
120void NuPlayer::Renderer::signalTimeDiscontinuity() {
Wei Jiabc2fb722014-07-08 16:37:57 -0700121 Mutex::Autolock autoLock(mLock);
Andreas Huber14f76722013-01-15 09:04:18 -0800122 // CHECK(mAudioQueue.empty());
123 // CHECK(mVideoQueue.empty());
Andy Hung09e0c362014-09-12 15:12:16 -0700124 mFirstAnchorTimeMediaUs = -1;
Andreas Huberf9334412010-12-15 15:17:42 -0800125 mAnchorTimeMediaUs = -1;
126 mAnchorTimeRealUs = -1;
Andreas Huber14f76722013-01-15 09:04:18 -0800127 mSyncQueues = false;
Andreas Huberf9334412010-12-15 15:17:42 -0800128}
129
Wei Jia28a8a9f2014-08-18 11:29:50 -0700130void NuPlayer::Renderer::signalAudioSinkChanged() {
131 (new AMessage(kWhatAudioSinkChanged, id()))->post();
132}
133
134void NuPlayer::Renderer::signalDisableOffloadAudio() {
135 (new AMessage(kWhatDisableOffloadAudio, id()))->post();
136}
137
Andreas Huberb4082222011-01-20 15:23:04 -0800138void NuPlayer::Renderer::pause() {
139 (new AMessage(kWhatPause, id()))->post();
140}
141
142void NuPlayer::Renderer::resume() {
143 (new AMessage(kWhatResume, id()))->post();
144}
145
Andreas Huberf9334412010-12-15 15:17:42 -0800146void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
147 switch (msg->what()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700148 case kWhatStopAudioSink:
149 {
150 mAudioSink->stop();
151 break;
152 }
153
Andreas Huberf9334412010-12-15 15:17:42 -0800154 case kWhatDrainAudioQueue:
155 {
156 int32_t generation;
157 CHECK(msg->findInt32("generation", &generation));
158 if (generation != mAudioQueueGeneration) {
159 break;
160 }
161
162 mDrainAudioQueuePending = false;
163
Andreas Huber078cfcf2011-09-15 12:25:04 -0700164 if (onDrainAudioQueue()) {
165 uint32_t numFramesPlayed;
166 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
167 (status_t)OK);
Andreas Huberf9334412010-12-15 15:17:42 -0800168
Andreas Huber078cfcf2011-09-15 12:25:04 -0700169 uint32_t numFramesPendingPlayout =
170 mNumFramesWritten - numFramesPlayed;
171
172 // This is how long the audio sink will have data to
173 // play back.
174 int64_t delayUs =
175 mAudioSink->msecsPerFrame()
176 * numFramesPendingPlayout * 1000ll;
177
178 // Let's give it more data after about half that time
179 // has elapsed.
Wei Jiabc2fb722014-07-08 16:37:57 -0700180 // kWhatDrainAudioQueue is used for non-offloading mode,
181 // and mLock is used only for offloading mode. Therefore,
182 // no need to acquire mLock here.
183 postDrainAudioQueue_l(delayUs / 2);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700184 }
Andreas Huberf9334412010-12-15 15:17:42 -0800185 break;
186 }
187
188 case kWhatDrainVideoQueue:
189 {
190 int32_t generation;
191 CHECK(msg->findInt32("generation", &generation));
192 if (generation != mVideoQueueGeneration) {
193 break;
194 }
195
196 mDrainVideoQueuePending = false;
197
198 onDrainVideoQueue();
199
200 postDrainVideoQueue();
201 break;
202 }
203
204 case kWhatQueueBuffer:
205 {
206 onQueueBuffer(msg);
207 break;
208 }
209
210 case kWhatQueueEOS:
211 {
212 onQueueEOS(msg);
213 break;
214 }
215
216 case kWhatFlush:
217 {
218 onFlush(msg);
219 break;
220 }
221
Andreas Huber3831a062010-12-21 10:22:33 -0800222 case kWhatAudioSinkChanged:
223 {
224 onAudioSinkChanged();
225 break;
226 }
227
Wei Jiabc2fb722014-07-08 16:37:57 -0700228 case kWhatDisableOffloadAudio:
229 {
230 onDisableOffloadAudio();
231 break;
232 }
233
Andreas Huberb4082222011-01-20 15:23:04 -0800234 case kWhatPause:
235 {
236 onPause();
237 break;
238 }
239
240 case kWhatResume:
241 {
242 onResume();
243 break;
244 }
245
Wei Jia3a2956d2014-07-22 16:01:33 -0700246 case kWhatAudioOffloadTearDown:
247 {
248 onAudioOffloadTearDown();
249 break;
250 }
251
Ronghua Wuf5b1db12014-09-09 10:11:08 -0700252 case kWhatAudioOffloadPauseTimeout:
253 {
254 int32_t generation;
255 CHECK(msg->findInt32("generation", &generation));
256 if (generation != mAudioOffloadPauseTimeoutGeneration) {
257 break;
258 }
259 onAudioOffloadTearDown();
260 break;
261 }
262
Andreas Huberf9334412010-12-15 15:17:42 -0800263 default:
264 TRESPASS();
265 break;
266 }
267}
268
Wei Jiabc2fb722014-07-08 16:37:57 -0700269void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
270 if (mDrainAudioQueuePending || mSyncQueues || mPaused
271 || offloadingAudio()) {
Andreas Huberf9334412010-12-15 15:17:42 -0800272 return;
273 }
274
275 if (mAudioQueue.empty()) {
276 return;
277 }
278
279 mDrainAudioQueuePending = true;
280 sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
281 msg->setInt32("generation", mAudioQueueGeneration);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700282 msg->post(delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800283}
284
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700285void NuPlayer::Renderer::prepareForMediaRenderingStart() {
286 mAudioRenderingStartGeneration = mAudioQueueGeneration;
287 mVideoRenderingStartGeneration = mVideoQueueGeneration;
288}
289
290void NuPlayer::Renderer::notifyIfMediaRenderingStarted() {
291 if (mVideoRenderingStartGeneration == mVideoQueueGeneration &&
292 mAudioRenderingStartGeneration == mAudioQueueGeneration) {
293 mVideoRenderingStartGeneration = -1;
294 mAudioRenderingStartGeneration = -1;
295
296 sp<AMessage> notify = mNotify->dup();
297 notify->setInt32("what", kWhatMediaRenderingStart);
298 notify->post();
299 }
300}
301
Wei Jiabc2fb722014-07-08 16:37:57 -0700302// static
303size_t NuPlayer::Renderer::AudioSinkCallback(
304 MediaPlayerBase::AudioSink * /* audioSink */,
305 void *buffer,
306 size_t size,
307 void *cookie,
308 MediaPlayerBase::AudioSink::cb_event_t event) {
309 NuPlayer::Renderer *me = (NuPlayer::Renderer *)cookie;
310
311 switch (event) {
312 case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
313 {
314 return me->fillAudioBuffer(buffer, size);
315 break;
316 }
317
318 case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
319 {
320 me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
321 break;
322 }
323
324 case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
325 {
Wei Jia3a2956d2014-07-22 16:01:33 -0700326 me->notifyAudioOffloadTearDown();
Wei Jiabc2fb722014-07-08 16:37:57 -0700327 break;
328 }
329 }
330
331 return 0;
332}
333
334size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
335 Mutex::Autolock autoLock(mLock);
336
Wei Jia73ddd212014-08-29 16:33:49 -0700337 if (!offloadingAudio() || mPaused) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700338 return 0;
339 }
340
341 bool hasEOS = false;
342
343 size_t sizeCopied = 0;
Ronghua Wu3e5efb32014-08-18 16:27:08 -0700344 bool firstEntry = true;
Wei Jiabc2fb722014-07-08 16:37:57 -0700345 while (sizeCopied < size && !mAudioQueue.empty()) {
346 QueueEntry *entry = &*mAudioQueue.begin();
347
348 if (entry->mBuffer == NULL) { // EOS
349 hasEOS = true;
350 mAudioQueue.erase(mAudioQueue.begin());
351 entry = NULL;
352 break;
353 }
354
Ronghua Wu3e5efb32014-08-18 16:27:08 -0700355 if (firstEntry && entry->mOffset == 0) {
356 firstEntry = false;
Wei Jiabc2fb722014-07-08 16:37:57 -0700357 int64_t mediaTimeUs;
358 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
359 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
Andy Hung09e0c362014-09-12 15:12:16 -0700360 if (mFirstAnchorTimeMediaUs == -1) {
361 mFirstAnchorTimeMediaUs = mediaTimeUs;
Wei Jiabc2fb722014-07-08 16:37:57 -0700362 }
Wei Jiabc2fb722014-07-08 16:37:57 -0700363
Lajos Molnar06ad1522014-08-28 07:27:44 -0700364 int64_t nowUs = ALooper::GetNowUs();
365 mAnchorTimeMediaUs =
Andy Hung09e0c362014-09-12 15:12:16 -0700366 mFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
Lajos Molnar06ad1522014-08-28 07:27:44 -0700367 mAnchorTimeRealUs = nowUs;
Andy Hung09e0c362014-09-12 15:12:16 -0700368
369 notifyPosition();
Wei Jiabc2fb722014-07-08 16:37:57 -0700370 }
371
372 size_t copy = entry->mBuffer->size() - entry->mOffset;
373 size_t sizeRemaining = size - sizeCopied;
374 if (copy > sizeRemaining) {
375 copy = sizeRemaining;
376 }
377
378 memcpy((char *)buffer + sizeCopied,
379 entry->mBuffer->data() + entry->mOffset,
380 copy);
381
382 entry->mOffset += copy;
383 if (entry->mOffset == entry->mBuffer->size()) {
384 entry->mNotifyConsumed->post();
385 mAudioQueue.erase(mAudioQueue.begin());
386 entry = NULL;
387 }
388 sizeCopied += copy;
389 notifyIfMediaRenderingStarted();
390 }
391
Wei Jiabc2fb722014-07-08 16:37:57 -0700392 if (hasEOS) {
393 (new AMessage(kWhatStopAudioSink, id()))->post();
394 }
395
396 return sizeCopied;
397}
398
Andreas Huber078cfcf2011-09-15 12:25:04 -0700399bool NuPlayer::Renderer::onDrainAudioQueue() {
400 uint32_t numFramesPlayed;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700401 if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
402 return false;
403 }
Andreas Huberc92fd242011-08-16 13:48:44 -0700404
Andreas Huber078cfcf2011-09-15 12:25:04 -0700405 ssize_t numFramesAvailableToWrite =
406 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
407
408#if 0
409 if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
Steve Blockdf64d152012-01-04 20:05:49 +0000410 ALOGI("audio sink underrun");
Andreas Huber078cfcf2011-09-15 12:25:04 -0700411 } else {
Steve Block3856b092011-10-20 11:56:00 +0100412 ALOGV("audio queue has %d frames left to play",
Andreas Huber078cfcf2011-09-15 12:25:04 -0700413 mAudioSink->frameCount() - numFramesAvailableToWrite);
414 }
415#endif
416
417 size_t numBytesAvailableToWrite =
418 numFramesAvailableToWrite * mAudioSink->frameSize();
419
420 while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
Andreas Huberc92fd242011-08-16 13:48:44 -0700421 QueueEntry *entry = &*mAudioQueue.begin();
422
423 if (entry->mBuffer == NULL) {
424 // EOS
Ronghua Wu5095d702014-08-27 12:05:48 -0700425 int64_t postEOSDelayUs = 0;
426 if (mAudioSink->needsTrailingPadding()) {
Lajos Molnar06ad1522014-08-28 07:27:44 -0700427 postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
Ronghua Wu5095d702014-08-27 12:05:48 -0700428 }
429 notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
Andreas Huberc92fd242011-08-16 13:48:44 -0700430
431 mAudioQueue.erase(mAudioQueue.begin());
432 entry = NULL;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700433 return false;
Eric Laurent9b7d9502011-03-21 11:49:00 -0700434 }
435
Andreas Huberf9334412010-12-15 15:17:42 -0800436 if (entry->mOffset == 0) {
437 int64_t mediaTimeUs;
438 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
Steve Block3856b092011-10-20 11:56:00 +0100439 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
Andy Hung09e0c362014-09-12 15:12:16 -0700440 if (mFirstAnchorTimeMediaUs == -1) {
441 mFirstAnchorTimeMediaUs = mediaTimeUs;
442 }
Andreas Huberf9334412010-12-15 15:17:42 -0800443 mAnchorTimeMediaUs = mediaTimeUs;
444
Lajos Molnar06ad1522014-08-28 07:27:44 -0700445 int64_t nowUs = ALooper::GetNowUs();
446 mAnchorTimeRealUs = nowUs + getPendingAudioPlayoutDurationUs(nowUs);
Andy Hung09e0c362014-09-12 15:12:16 -0700447
448 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800449 }
450
451 size_t copy = entry->mBuffer->size() - entry->mOffset;
452 if (copy > numBytesAvailableToWrite) {
453 copy = numBytesAvailableToWrite;
454 }
455
Andy Hunga31335a2014-08-20 17:37:59 -0700456 ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy);
457 if (written < 0) {
458 // An error in AudioSink write is fatal here.
459 LOG_ALWAYS_FATAL("AudioSink write error(%zd) when writing %zu bytes", written, copy);
460 }
Andreas Huberf9334412010-12-15 15:17:42 -0800461
Andy Hunga31335a2014-08-20 17:37:59 -0700462 entry->mOffset += written;
Andreas Huberf9334412010-12-15 15:17:42 -0800463 if (entry->mOffset == entry->mBuffer->size()) {
464 entry->mNotifyConsumed->post();
465 mAudioQueue.erase(mAudioQueue.begin());
Eric Laurent9b7d9502011-03-21 11:49:00 -0700466
Andreas Huberf9334412010-12-15 15:17:42 -0800467 entry = NULL;
468 }
469
Andy Hunga31335a2014-08-20 17:37:59 -0700470 numBytesAvailableToWrite -= written;
471 size_t copiedFrames = written / mAudioSink->frameSize();
Andreas Huber078cfcf2011-09-15 12:25:04 -0700472 mNumFramesWritten += copiedFrames;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700473
474 notifyIfMediaRenderingStarted();
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800475
Andy Hunga31335a2014-08-20 17:37:59 -0700476 if (written != (ssize_t)copy) {
477 // A short count was received from AudioSink::write()
478 //
479 // AudioSink write should block until exactly the number of bytes are delivered.
480 // But it may return with a short count (without an error) when:
481 //
482 // 1) Size to be copied is not a multiple of the frame size. We consider this fatal.
483 // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
484
485 // (Case 1)
486 // Must be a multiple of the frame size. If it is not a multiple of a frame size, it
487 // needs to fail, as we should not carry over fractional frames between calls.
488 CHECK_EQ(copy % mAudioSink->frameSize(), 0);
489
490 // (Case 2)
491 // Return early to the caller.
492 // Beware of calling immediately again as this may busy-loop if you are not careful.
493 ALOGW("AudioSink write short frame count %zd < %zu", written, copy);
494 break;
495 }
496 }
Andreas Huber078cfcf2011-09-15 12:25:04 -0700497 return !mAudioQueue.empty();
Andreas Huberf9334412010-12-15 15:17:42 -0800498}
499
Lajos Molnar06ad1522014-08-28 07:27:44 -0700500int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
501 int64_t writtenAudioDurationUs =
502 mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame();
503 return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
Ronghua Wu5095d702014-08-27 12:05:48 -0700504}
505
Andreas Huberf9334412010-12-15 15:17:42 -0800506void NuPlayer::Renderer::postDrainVideoQueue() {
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700507 if (mDrainVideoQueuePending
508 || mSyncQueues
509 || (mPaused && mVideoSampleReceived)) {
Andreas Huberf9334412010-12-15 15:17:42 -0800510 return;
511 }
512
513 if (mVideoQueue.empty()) {
514 return;
515 }
516
517 QueueEntry &entry = *mVideoQueue.begin();
518
519 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
520 msg->setInt32("generation", mVideoQueueGeneration);
521
522 int64_t delayUs;
523
524 if (entry.mBuffer == NULL) {
525 // EOS doesn't carry a timestamp.
526 delayUs = 0;
Andreas Huberd5e56232013-03-12 11:01:43 -0700527 } else if (mFlags & FLAG_REAL_TIME) {
528 int64_t mediaTimeUs;
529 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
530
531 delayUs = mediaTimeUs - ALooper::GetNowUs();
Andreas Huberf9334412010-12-15 15:17:42 -0800532 } else {
533 int64_t mediaTimeUs;
534 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
535
Andy Hung09e0c362014-09-12 15:12:16 -0700536 if (mFirstAnchorTimeMediaUs == -1 && !mHasAudio) {
537 mFirstAnchorTimeMediaUs = mediaTimeUs;
538 }
Andreas Huberf9334412010-12-15 15:17:42 -0800539 if (mAnchorTimeMediaUs < 0) {
540 delayUs = 0;
541
Andreas Huber3831a062010-12-21 10:22:33 -0800542 if (!mHasAudio) {
Andreas Huberf9334412010-12-15 15:17:42 -0800543 mAnchorTimeMediaUs = mediaTimeUs;
544 mAnchorTimeRealUs = ALooper::GetNowUs();
Andy Hung09e0c362014-09-12 15:12:16 -0700545 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800546 }
547 } else {
548 int64_t realTimeUs =
549 (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs;
550
551 delayUs = realTimeUs - ALooper::GetNowUs();
552 }
553 }
554
Lajos Molnar09524832014-07-17 14:29:51 -0700555 ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800556 msg->post(delayUs);
557
558 mDrainVideoQueuePending = true;
559}
560
561void NuPlayer::Renderer::onDrainVideoQueue() {
562 if (mVideoQueue.empty()) {
563 return;
564 }
565
566 QueueEntry *entry = &*mVideoQueue.begin();
567
568 if (entry->mBuffer == NULL) {
569 // EOS
570
Andreas Huberc92fd242011-08-16 13:48:44 -0700571 notifyEOS(false /* audio */, entry->mFinalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800572
573 mVideoQueue.erase(mVideoQueue.begin());
574 entry = NULL;
Andreas Huber3fe62152011-09-16 15:09:22 -0700575
576 mVideoLateByUs = 0ll;
Andreas Huberf9334412010-12-15 15:17:42 -0800577 return;
578 }
579
Andreas Huberd5e56232013-03-12 11:01:43 -0700580 int64_t realTimeUs;
581 if (mFlags & FLAG_REAL_TIME) {
582 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
583 } else {
584 int64_t mediaTimeUs;
585 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
Andreas Huberf9334412010-12-15 15:17:42 -0800586
Andreas Huberd5e56232013-03-12 11:01:43 -0700587 realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
588 }
589
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700590 bool tooLate = false;
Andreas Huber3fe62152011-09-16 15:09:22 -0700591
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700592 if (!mPaused) {
593 mVideoLateByUs = ALooper::GetNowUs() - realTimeUs;
594 tooLate = (mVideoLateByUs > 40000);
595
596 if (tooLate) {
597 ALOGV("video late by %lld us (%.2f secs)",
598 mVideoLateByUs, mVideoLateByUs / 1E6);
599 } else {
600 ALOGV("rendering video at media time %.2f secs",
601 (mFlags & FLAG_REAL_TIME ? realTimeUs :
602 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6);
603 }
Andreas Huber078cfcf2011-09-15 12:25:04 -0700604 } else {
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700605 mVideoLateByUs = 0ll;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700606 }
Andreas Huberf9334412010-12-15 15:17:42 -0800607
Glenn Kasten683525b2011-11-04 18:05:35 -0700608 entry->mNotifyConsumed->setInt32("render", !tooLate);
Andreas Huberf9334412010-12-15 15:17:42 -0800609 entry->mNotifyConsumed->post();
610 mVideoQueue.erase(mVideoQueue.begin());
611 entry = NULL;
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800612
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700613 mVideoSampleReceived = true;
James Dongf57b4ea2012-07-20 13:38:36 -0700614
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700615 if (!mPaused) {
616 if (!mVideoRenderingStarted) {
617 mVideoRenderingStarted = true;
618 notifyVideoRenderingStart();
619 }
620 notifyIfMediaRenderingStarted();
621 }
Andreas Huberf9334412010-12-15 15:17:42 -0800622}
623
James Dongf57b4ea2012-07-20 13:38:36 -0700624void NuPlayer::Renderer::notifyVideoRenderingStart() {
625 sp<AMessage> notify = mNotify->dup();
626 notify->setInt32("what", kWhatVideoRenderingStart);
627 notify->post();
628}
629
Ronghua Wu5095d702014-08-27 12:05:48 -0700630void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
Andreas Huberf9334412010-12-15 15:17:42 -0800631 sp<AMessage> notify = mNotify->dup();
632 notify->setInt32("what", kWhatEOS);
633 notify->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huberc92fd242011-08-16 13:48:44 -0700634 notify->setInt32("finalResult", finalResult);
Ronghua Wu5095d702014-08-27 12:05:48 -0700635 notify->post(delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800636}
637
Wei Jia3a2956d2014-07-22 16:01:33 -0700638void NuPlayer::Renderer::notifyAudioOffloadTearDown() {
639 (new AMessage(kWhatAudioOffloadTearDown, id()))->post();
640}
641
Andreas Huberf9334412010-12-15 15:17:42 -0800642void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
643 int32_t audio;
644 CHECK(msg->findInt32("audio", &audio));
645
Andreas Huberbc7f5b22011-01-21 10:15:23 -0800646 if (audio) {
647 mHasAudio = true;
648 } else {
649 mHasVideo = true;
650 }
651
Andreas Huberf9334412010-12-15 15:17:42 -0800652 if (dropBufferWhileFlushing(audio, msg)) {
653 return;
654 }
655
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800656 sp<ABuffer> buffer;
657 CHECK(msg->findBuffer("buffer", &buffer));
Andreas Huberf9334412010-12-15 15:17:42 -0800658
659 sp<AMessage> notifyConsumed;
660 CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
661
662 QueueEntry entry;
663 entry.mBuffer = buffer;
664 entry.mNotifyConsumed = notifyConsumed;
665 entry.mOffset = 0;
666 entry.mFinalResult = OK;
667
668 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700669 Mutex::Autolock autoLock(mLock);
Andreas Huberf9334412010-12-15 15:17:42 -0800670 mAudioQueue.push_back(entry);
Wei Jiabc2fb722014-07-08 16:37:57 -0700671 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800672 } else {
673 mVideoQueue.push_back(entry);
674 postDrainVideoQueue();
675 }
676
Wei Jiabc2fb722014-07-08 16:37:57 -0700677 Mutex::Autolock autoLock(mLock);
Andreas Hubercb67cd12011-08-26 16:02:19 -0700678 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
679 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800680 }
Andreas Hubercb67cd12011-08-26 16:02:19 -0700681
682 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
683 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
684
685 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
686 // EOS signalled on either queue.
Wei Jiabc2fb722014-07-08 16:37:57 -0700687 syncQueuesDone_l();
Andreas Hubercb67cd12011-08-26 16:02:19 -0700688 return;
689 }
690
691 int64_t firstAudioTimeUs;
692 int64_t firstVideoTimeUs;
693 CHECK(firstAudioBuffer->meta()
694 ->findInt64("timeUs", &firstAudioTimeUs));
695 CHECK(firstVideoBuffer->meta()
696 ->findInt64("timeUs", &firstVideoTimeUs));
697
698 int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
699
Steve Block3856b092011-10-20 11:56:00 +0100700 ALOGV("queueDiff = %.2f secs", diff / 1E6);
Andreas Hubercb67cd12011-08-26 16:02:19 -0700701
702 if (diff > 100000ll) {
703 // Audio data starts More than 0.1 secs before video.
704 // Drop some audio.
705
706 (*mAudioQueue.begin()).mNotifyConsumed->post();
707 mAudioQueue.erase(mAudioQueue.begin());
708 return;
709 }
710
Wei Jiabc2fb722014-07-08 16:37:57 -0700711 syncQueuesDone_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800712}
713
Wei Jiabc2fb722014-07-08 16:37:57 -0700714void NuPlayer::Renderer::syncQueuesDone_l() {
Andreas Huberf9334412010-12-15 15:17:42 -0800715 if (!mSyncQueues) {
716 return;
717 }
718
719 mSyncQueues = false;
720
721 if (!mAudioQueue.empty()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700722 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800723 }
724
725 if (!mVideoQueue.empty()) {
726 postDrainVideoQueue();
727 }
728}
729
730void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {
731 int32_t audio;
732 CHECK(msg->findInt32("audio", &audio));
733
734 if (dropBufferWhileFlushing(audio, msg)) {
735 return;
736 }
737
738 int32_t finalResult;
739 CHECK(msg->findInt32("finalResult", &finalResult));
740
741 QueueEntry entry;
742 entry.mOffset = 0;
743 entry.mFinalResult = finalResult;
744
745 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700746 Mutex::Autolock autoLock(mLock);
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100747 if (mAudioQueue.empty() && mSyncQueues) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700748 syncQueuesDone_l();
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100749 }
Andreas Huberf9334412010-12-15 15:17:42 -0800750 mAudioQueue.push_back(entry);
Wei Jiabc2fb722014-07-08 16:37:57 -0700751 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800752 } else {
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100753 if (mVideoQueue.empty() && mSyncQueues) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700754 Mutex::Autolock autoLock(mLock);
755 syncQueuesDone_l();
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100756 }
Andreas Huberf9334412010-12-15 15:17:42 -0800757 mVideoQueue.push_back(entry);
758 postDrainVideoQueue();
759 }
760}
761
762void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
763 int32_t audio;
764 CHECK(msg->findInt32("audio", &audio));
765
Wei Jia28a8a9f2014-08-18 11:29:50 -0700766 {
767 Mutex::Autolock autoLock(mFlushLock);
768 if (audio) {
769 mFlushingAudio = false;
770 } else {
771 mFlushingVideo = false;
772 }
773 }
774
Andreas Huberf9334412010-12-15 15:17:42 -0800775 // If we're currently syncing the queues, i.e. dropping audio while
776 // aligning the first audio/video buffer times and only one of the
777 // two queues has data, we may starve that queue by not requesting
778 // more buffers from the decoder. If the other source then encounters
779 // a discontinuity that leads to flushing, we'll never find the
780 // corresponding discontinuity on the other queue.
781 // Therefore we'll stop syncing the queues if at least one of them
782 // is flushed.
Wei Jiabc2fb722014-07-08 16:37:57 -0700783 {
784 Mutex::Autolock autoLock(mLock);
785 syncQueuesDone_l();
786 }
Andreas Huberf9334412010-12-15 15:17:42 -0800787
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700788 ALOGV("flushing %s", audio ? "audio" : "video");
Andreas Huberf9334412010-12-15 15:17:42 -0800789 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700790 {
791 Mutex::Autolock autoLock(mLock);
792 flushQueue(&mAudioQueue);
Wei Jia28a8a9f2014-08-18 11:29:50 -0700793
794 ++mAudioQueueGeneration;
795 prepareForMediaRenderingStart();
796
797 if (offloadingAudio()) {
Andy Hung09e0c362014-09-12 15:12:16 -0700798 mFirstAnchorTimeMediaUs = -1;
Wei Jia28a8a9f2014-08-18 11:29:50 -0700799 }
Wei Jiabc2fb722014-07-08 16:37:57 -0700800 }
Andreas Huberf9334412010-12-15 15:17:42 -0800801
Andreas Huberf9334412010-12-15 15:17:42 -0800802 mDrainAudioQueuePending = false;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700803
Wei Jiabc2fb722014-07-08 16:37:57 -0700804 if (offloadingAudio()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700805 mAudioSink->pause();
806 mAudioSink->flush();
807 mAudioSink->start();
808 }
Andreas Huberf9334412010-12-15 15:17:42 -0800809 } else {
810 flushQueue(&mVideoQueue);
811
Andreas Huberf9334412010-12-15 15:17:42 -0800812 mDrainVideoQueuePending = false;
813 ++mVideoQueueGeneration;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700814
815 prepareForMediaRenderingStart();
Andreas Huberf9334412010-12-15 15:17:42 -0800816 }
817
Chong Zhangfbe8bef2014-08-29 18:34:17 -0700818 mVideoSampleReceived = false;
Andreas Huberf9334412010-12-15 15:17:42 -0800819 notifyFlushComplete(audio);
820}
821
822void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) {
823 while (!queue->empty()) {
824 QueueEntry *entry = &*queue->begin();
825
826 if (entry->mBuffer != NULL) {
827 entry->mNotifyConsumed->post();
828 }
829
830 queue->erase(queue->begin());
831 entry = NULL;
832 }
833}
834
835void NuPlayer::Renderer::notifyFlushComplete(bool audio) {
836 sp<AMessage> notify = mNotify->dup();
837 notify->setInt32("what", kWhatFlushComplete);
838 notify->setInt32("audio", static_cast<int32_t>(audio));
839 notify->post();
840}
841
842bool NuPlayer::Renderer::dropBufferWhileFlushing(
843 bool audio, const sp<AMessage> &msg) {
844 bool flushing = false;
845
846 {
847 Mutex::Autolock autoLock(mFlushLock);
848 if (audio) {
849 flushing = mFlushingAudio;
850 } else {
851 flushing = mFlushingVideo;
852 }
853 }
854
855 if (!flushing) {
856 return false;
857 }
858
859 sp<AMessage> notifyConsumed;
860 if (msg->findMessage("notifyConsumed", &notifyConsumed)) {
861 notifyConsumed->post();
862 }
863
864 return true;
865}
866
Andreas Huber3831a062010-12-21 10:22:33 -0800867void NuPlayer::Renderer::onAudioSinkChanged() {
Wei Jiabc2fb722014-07-08 16:37:57 -0700868 if (offloadingAudio()) {
869 return;
870 }
Andreas Huber3831a062010-12-21 10:22:33 -0800871 CHECK(!mDrainAudioQueuePending);
872 mNumFramesWritten = 0;
Marco Nelissen4110c102012-03-29 09:31:28 -0700873 uint32_t written;
874 if (mAudioSink->getFramesWritten(&written) == OK) {
875 mNumFramesWritten = written;
876 }
Andreas Huber3831a062010-12-21 10:22:33 -0800877}
878
Wei Jiabc2fb722014-07-08 16:37:57 -0700879void NuPlayer::Renderer::onDisableOffloadAudio() {
880 Mutex::Autolock autoLock(mLock);
881 mFlags &= ~FLAG_OFFLOAD_AUDIO;
Wei Jia3a2956d2014-07-22 16:01:33 -0700882 ++mAudioQueueGeneration;
Wei Jiabc2fb722014-07-08 16:37:57 -0700883}
884
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800885void NuPlayer::Renderer::notifyPosition() {
Andy Hung09e0c362014-09-12 15:12:16 -0700886 // notifyPosition() must be called only after setting mAnchorTimeRealUs
887 // and mAnchorTimeMediaUs, and must not be paused as it extrapolates position.
888 //CHECK_GE(mAnchorTimeRealUs, 0);
889 //CHECK_GE(mAnchorTimeMediaUs, 0);
890 //CHECK(!mPaused || !mHasAudio); // video-only does display in paused mode.
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800891
892 int64_t nowUs = ALooper::GetNowUs();
Andreas Huber714aa7b2011-09-13 08:28:38 -0700893
894 if (mLastPositionUpdateUs >= 0
895 && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
896 return;
897 }
898 mLastPositionUpdateUs = nowUs;
899
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800900 int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
901
Andy Hung09e0c362014-09-12 15:12:16 -0700902 //ALOGD("notifyPosition: positionUs(%lld) nowUs(%lld) mAnchorTimeRealUs(%lld)"
903 // " mAnchorTimeMediaUs(%lld) mFirstAnchorTimeMediaUs(%lld)",
904 // (long long)positionUs, (long long)nowUs, (long long)mAnchorTimeRealUs,
905 // (long long)mAnchorTimeMediaUs, (long long)mFirstAnchorTimeMediaUs);
906
907 // Due to adding the latency to mAnchorTimeRealUs in onDrainAudioQueue(),
908 // positionUs may be less than the first media time. This is avoided
909 // here to prevent potential retrograde motion of the position bar
910 // when starting up after a seek.
911 if (positionUs < mFirstAnchorTimeMediaUs) {
912 positionUs = mFirstAnchorTimeMediaUs;
913 }
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800914 sp<AMessage> notify = mNotify->dup();
915 notify->setInt32("what", kWhatPosition);
916 notify->setInt64("positionUs", positionUs);
Andreas Huber3fe62152011-09-16 15:09:22 -0700917 notify->setInt64("videoLateByUs", mVideoLateByUs);
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800918 notify->post();
919}
920
Andreas Huberb4082222011-01-20 15:23:04 -0800921void NuPlayer::Renderer::onPause() {
Rachad8592dbb2014-09-09 13:10:28 -0700922 if (mPaused) {
923 ALOGW("Renderer::onPause() called while already paused!");
924 return;
925 }
Wei Jia28a8a9f2014-08-18 11:29:50 -0700926 {
927 Mutex::Autolock autoLock(mLock);
928 ++mAudioQueueGeneration;
929 ++mVideoQueueGeneration;
930 prepareForMediaRenderingStart();
Wei Jia73ddd212014-08-29 16:33:49 -0700931 mPaused = true;
Wei Jia28a8a9f2014-08-18 11:29:50 -0700932 }
933
Andreas Huberb4082222011-01-20 15:23:04 -0800934 mDrainAudioQueuePending = false;
Andreas Huberb4082222011-01-20 15:23:04 -0800935 mDrainVideoQueuePending = false;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700936
Andreas Huberb4082222011-01-20 15:23:04 -0800937 if (mHasAudio) {
938 mAudioSink->pause();
Ronghua Wuf5b1db12014-09-09 10:11:08 -0700939 startAudioOffloadPauseTimeout();
Andreas Huberb4082222011-01-20 15:23:04 -0800940 }
941
Andreas Huberea9d51b2011-11-30 09:53:40 -0800942 ALOGV("now paused audio queue has %d entries, video has %d entries",
943 mAudioQueue.size(), mVideoQueue.size());
Andreas Huberb4082222011-01-20 15:23:04 -0800944}
945
946void NuPlayer::Renderer::onResume() {
Andreas Huberb58ce9f2011-11-28 16:27:35 -0800947 if (!mPaused) {
948 return;
949 }
Andreas Huberb4082222011-01-20 15:23:04 -0800950
951 if (mHasAudio) {
Ronghua Wuf5b1db12014-09-09 10:11:08 -0700952 cancelAudioOffloadPauseTimeout();
Andreas Huberb4082222011-01-20 15:23:04 -0800953 mAudioSink->start();
954 }
955
Wei Jia73ddd212014-08-29 16:33:49 -0700956 Mutex::Autolock autoLock(mLock);
Andreas Huberb4082222011-01-20 15:23:04 -0800957 mPaused = false;
958
959 if (!mAudioQueue.empty()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700960 postDrainAudioQueue_l();
Andreas Huberb4082222011-01-20 15:23:04 -0800961 }
962
963 if (!mVideoQueue.empty()) {
964 postDrainVideoQueue();
965 }
966}
967
Andy Hung09e0c362014-09-12 15:12:16 -0700968// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs()
969// as it acquires locks and may query the audio driver.
970//
971// Some calls are not needed since notifyPosition() doesn't always deliver a message.
972// Some calls could conceivably retrieve extrapolated data instead of
973// accessing getTimestamp() or getPosition() every time a data buffer with
974// a media time is received.
975//
Lajos Molnar06ad1522014-08-28 07:27:44 -0700976int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
Wei Jia3a2956d2014-07-22 16:01:33 -0700977 uint32_t numFramesPlayed;
Lajos Molnar06ad1522014-08-28 07:27:44 -0700978 int64_t numFramesPlayedAt;
979 AudioTimestamp ts;
Andy Hung09e0c362014-09-12 15:12:16 -0700980 static const int64_t kStaleTimestamp100ms = 100000;
981
Lajos Molnar06ad1522014-08-28 07:27:44 -0700982 status_t res = mAudioSink->getTimestamp(ts);
Andy Hung09e0c362014-09-12 15:12:16 -0700983 if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
Lajos Molnar06ad1522014-08-28 07:27:44 -0700984 numFramesPlayed = ts.mPosition;
985 numFramesPlayedAt =
986 ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
Andy Hung09e0c362014-09-12 15:12:16 -0700987 const int64_t timestampAge = nowUs - numFramesPlayedAt;
988 if (timestampAge > kStaleTimestamp100ms) {
989 // This is an audio FIXME.
990 // getTimestamp returns a timestamp which may come from audio mixing threads.
991 // After pausing, the MixerThread may go idle, thus the mTime estimate may
992 // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
993 // the max latency should be about 25ms with an average around 12ms (to be verified).
994 // For safety we use 100ms.
995 ALOGW("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
996 (long long)nowUs, (long long)numFramesPlayedAt);
997 numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
998 }
999 //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
1000 } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
1001 numFramesPlayed = 0;
1002 numFramesPlayedAt = nowUs;
1003 //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
1004 // numFramesPlayed, (long long)numFramesPlayedAt);
1005 } else { // case 3: transitory at new track or audio fast tracks.
Lajos Molnar06ad1522014-08-28 07:27:44 -07001006 res = mAudioSink->getPosition(&numFramesPlayed);
1007 CHECK_EQ(res, (status_t)OK);
1008 numFramesPlayedAt = nowUs;
1009 numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
Andy Hung09e0c362014-09-12 15:12:16 -07001010 //ALOGD("getPosition: %d %lld", numFramesPlayed, numFramesPlayedAt);
Lajos Molnar06ad1522014-08-28 07:27:44 -07001011 }
Andy Hung09e0c362014-09-12 15:12:16 -07001012
1013 // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
1014 //CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
1015 int64_t durationUs = (int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame()
Lajos Molnar06ad1522014-08-28 07:27:44 -07001016 + nowUs - numFramesPlayedAt;
Andy Hung09e0c362014-09-12 15:12:16 -07001017 if (durationUs < 0) {
1018 // Occurs when numFramesPlayed position is very small and the following:
1019 // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
1020 // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
1021 // (2) In case 3, using getPosition and adding mAudioSink->latency() to
1022 // numFramesPlayedAt, by a time amount greater than numFramesPlayed.
1023 //
1024 // Both of these are transitory conditions.
1025 ALOGW("getPlayedOutAudioDurationUs: negative timestamp %lld set to zero", (long long)durationUs);
1026 durationUs = 0;
1027 }
1028 ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
1029 (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
1030 return durationUs;
Lajos Molnar06ad1522014-08-28 07:27:44 -07001031}
Wei Jia3a2956d2014-07-22 16:01:33 -07001032
Lajos Molnar06ad1522014-08-28 07:27:44 -07001033void NuPlayer::Renderer::onAudioOffloadTearDown() {
Ronghua Wuf5b1db12014-09-09 10:11:08 -07001034 if (mAudioOffloadTornDown) {
1035 return;
1036 }
1037 mAudioOffloadTornDown = true;
1038
Wei Jia28a8a9f2014-08-18 11:29:50 -07001039 int64_t firstAudioTimeUs;
1040 {
1041 Mutex::Autolock autoLock(mLock);
Andy Hung09e0c362014-09-12 15:12:16 -07001042 firstAudioTimeUs = mFirstAnchorTimeMediaUs;
Wei Jia28a8a9f2014-08-18 11:29:50 -07001043 }
Lajos Molnar06ad1522014-08-28 07:27:44 -07001044
1045 int64_t currentPositionUs =
1046 firstAudioTimeUs + getPlayedOutAudioDurationUs(ALooper::GetNowUs());
Wei Jia3a2956d2014-07-22 16:01:33 -07001047
1048 mAudioSink->stop();
1049 mAudioSink->flush();
1050
1051 sp<AMessage> notify = mNotify->dup();
1052 notify->setInt32("what", kWhatAudioOffloadTearDown);
1053 notify->setInt64("positionUs", currentPositionUs);
1054 notify->post();
1055}
1056
Ronghua Wuf5b1db12014-09-09 10:11:08 -07001057void NuPlayer::Renderer::startAudioOffloadPauseTimeout() {
1058 if (offloadingAudio()) {
1059 sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, id());
1060 msg->setInt32("generation", mAudioOffloadPauseTimeoutGeneration);
1061 msg->post(kOffloadPauseMaxUs);
1062 }
1063}
1064
1065void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() {
1066 if (offloadingAudio()) {
1067 ++mAudioOffloadPauseTimeoutGeneration;
1068 }
1069}
1070
Andreas Huberf9334412010-12-15 15:17:42 -08001071} // namespace android
1072