blob: a070c1a77e93456adc24f0af732ea6e4dffc40a6 [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>
Andreas Huberf9334412010-12-15 15:17:42 -080026
27namespace android {
28
Andreas Huber714aa7b2011-09-13 08:28:38 -070029// static
30const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
31
Andreas Huberf9334412010-12-15 15:17:42 -080032NuPlayer::Renderer::Renderer(
33 const sp<MediaPlayerBase::AudioSink> &sink,
Andreas Huberd5e56232013-03-12 11:01:43 -070034 const sp<AMessage> &notify,
35 uint32_t flags)
Andreas Huberf9334412010-12-15 15:17:42 -080036 : mAudioSink(sink),
37 mNotify(notify),
Andreas Huberd5e56232013-03-12 11:01:43 -070038 mFlags(flags),
Andreas Huberf9334412010-12-15 15:17:42 -080039 mNumFramesWritten(0),
40 mDrainAudioQueuePending(false),
41 mDrainVideoQueuePending(false),
42 mAudioQueueGeneration(0),
43 mVideoQueueGeneration(0),
44 mAnchorTimeMediaUs(-1),
45 mAnchorTimeRealUs(-1),
46 mFlushingAudio(false),
47 mFlushingVideo(false),
Andreas Huberbc7f5b22011-01-21 10:15:23 -080048 mHasAudio(false),
49 mHasVideo(false),
50 mSyncQueues(false),
Andreas Huber714aa7b2011-09-13 08:28:38 -070051 mPaused(false),
James Dongf57b4ea2012-07-20 13:38:36 -070052 mVideoRenderingStarted(false),
Lajos Molnarcbaffcf2013-08-14 18:30:38 -070053 mVideoRenderingStartGeneration(0),
54 mAudioRenderingStartGeneration(0),
Andreas Huber3fe62152011-09-16 15:09:22 -070055 mLastPositionUpdateUs(-1ll),
56 mVideoLateByUs(0ll) {
Andreas Huberf9334412010-12-15 15:17:42 -080057}
58
59NuPlayer::Renderer::~Renderer() {
60}
61
62void NuPlayer::Renderer::queueBuffer(
63 bool audio,
64 const sp<ABuffer> &buffer,
65 const sp<AMessage> &notifyConsumed) {
66 sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
67 msg->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huber2d8bedd2012-02-21 14:38:23 -080068 msg->setBuffer("buffer", buffer);
Andreas Huberf9334412010-12-15 15:17:42 -080069 msg->setMessage("notifyConsumed", notifyConsumed);
70 msg->post();
71}
72
73void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
74 CHECK_NE(finalResult, (status_t)OK);
75
76 sp<AMessage> msg = new AMessage(kWhatQueueEOS, id());
77 msg->setInt32("audio", static_cast<int32_t>(audio));
78 msg->setInt32("finalResult", finalResult);
79 msg->post();
80}
81
82void NuPlayer::Renderer::flush(bool audio) {
83 {
84 Mutex::Autolock autoLock(mFlushLock);
85 if (audio) {
86 CHECK(!mFlushingAudio);
87 mFlushingAudio = true;
88 } else {
89 CHECK(!mFlushingVideo);
90 mFlushingVideo = true;
91 }
92 }
93
94 sp<AMessage> msg = new AMessage(kWhatFlush, id());
95 msg->setInt32("audio", static_cast<int32_t>(audio));
96 msg->post();
97}
98
99void NuPlayer::Renderer::signalTimeDiscontinuity() {
Andreas Huber14f76722013-01-15 09:04:18 -0800100 // CHECK(mAudioQueue.empty());
101 // CHECK(mVideoQueue.empty());
Andreas Huberf9334412010-12-15 15:17:42 -0800102 mAnchorTimeMediaUs = -1;
103 mAnchorTimeRealUs = -1;
Andreas Huber14f76722013-01-15 09:04:18 -0800104 mSyncQueues = false;
Andreas Huberf9334412010-12-15 15:17:42 -0800105}
106
Andreas Huberb4082222011-01-20 15:23:04 -0800107void NuPlayer::Renderer::pause() {
108 (new AMessage(kWhatPause, id()))->post();
109}
110
111void NuPlayer::Renderer::resume() {
112 (new AMessage(kWhatResume, id()))->post();
113}
114
Andreas Huberf9334412010-12-15 15:17:42 -0800115void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
116 switch (msg->what()) {
117 case kWhatDrainAudioQueue:
118 {
119 int32_t generation;
120 CHECK(msg->findInt32("generation", &generation));
121 if (generation != mAudioQueueGeneration) {
122 break;
123 }
124
125 mDrainAudioQueuePending = false;
126
Andreas Huber078cfcf2011-09-15 12:25:04 -0700127 if (onDrainAudioQueue()) {
128 uint32_t numFramesPlayed;
129 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
130 (status_t)OK);
Andreas Huberf9334412010-12-15 15:17:42 -0800131
Andreas Huber078cfcf2011-09-15 12:25:04 -0700132 uint32_t numFramesPendingPlayout =
133 mNumFramesWritten - numFramesPlayed;
134
135 // This is how long the audio sink will have data to
136 // play back.
137 int64_t delayUs =
138 mAudioSink->msecsPerFrame()
139 * numFramesPendingPlayout * 1000ll;
140
141 // Let's give it more data after about half that time
142 // has elapsed.
143 postDrainAudioQueue(delayUs / 2);
144 }
Andreas Huberf9334412010-12-15 15:17:42 -0800145 break;
146 }
147
148 case kWhatDrainVideoQueue:
149 {
150 int32_t generation;
151 CHECK(msg->findInt32("generation", &generation));
152 if (generation != mVideoQueueGeneration) {
153 break;
154 }
155
156 mDrainVideoQueuePending = false;
157
158 onDrainVideoQueue();
159
160 postDrainVideoQueue();
161 break;
162 }
163
164 case kWhatQueueBuffer:
165 {
166 onQueueBuffer(msg);
167 break;
168 }
169
170 case kWhatQueueEOS:
171 {
172 onQueueEOS(msg);
173 break;
174 }
175
176 case kWhatFlush:
177 {
178 onFlush(msg);
179 break;
180 }
181
Andreas Huber3831a062010-12-21 10:22:33 -0800182 case kWhatAudioSinkChanged:
183 {
184 onAudioSinkChanged();
185 break;
186 }
187
Andreas Huberb4082222011-01-20 15:23:04 -0800188 case kWhatPause:
189 {
190 onPause();
191 break;
192 }
193
194 case kWhatResume:
195 {
196 onResume();
197 break;
198 }
199
Andreas Huberf9334412010-12-15 15:17:42 -0800200 default:
201 TRESPASS();
202 break;
203 }
204}
205
Andreas Huber078cfcf2011-09-15 12:25:04 -0700206void NuPlayer::Renderer::postDrainAudioQueue(int64_t delayUs) {
Andreas Huberb4082222011-01-20 15:23:04 -0800207 if (mDrainAudioQueuePending || mSyncQueues || mPaused) {
Andreas Huberf9334412010-12-15 15:17:42 -0800208 return;
209 }
210
211 if (mAudioQueue.empty()) {
212 return;
213 }
214
215 mDrainAudioQueuePending = true;
216 sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
217 msg->setInt32("generation", mAudioQueueGeneration);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700218 msg->post(delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800219}
220
Andreas Huber3831a062010-12-21 10:22:33 -0800221void NuPlayer::Renderer::signalAudioSinkChanged() {
222 (new AMessage(kWhatAudioSinkChanged, id()))->post();
223}
224
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700225void NuPlayer::Renderer::prepareForMediaRenderingStart() {
226 mAudioRenderingStartGeneration = mAudioQueueGeneration;
227 mVideoRenderingStartGeneration = mVideoQueueGeneration;
228}
229
230void NuPlayer::Renderer::notifyIfMediaRenderingStarted() {
231 if (mVideoRenderingStartGeneration == mVideoQueueGeneration &&
232 mAudioRenderingStartGeneration == mAudioQueueGeneration) {
233 mVideoRenderingStartGeneration = -1;
234 mAudioRenderingStartGeneration = -1;
235
236 sp<AMessage> notify = mNotify->dup();
237 notify->setInt32("what", kWhatMediaRenderingStart);
238 notify->post();
239 }
240}
241
Andreas Huber078cfcf2011-09-15 12:25:04 -0700242bool NuPlayer::Renderer::onDrainAudioQueue() {
243 uint32_t numFramesPlayed;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700244 if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
245 return false;
246 }
Andreas Huberc92fd242011-08-16 13:48:44 -0700247
Andreas Huber078cfcf2011-09-15 12:25:04 -0700248 ssize_t numFramesAvailableToWrite =
249 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
250
251#if 0
252 if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
Steve Blockdf64d152012-01-04 20:05:49 +0000253 ALOGI("audio sink underrun");
Andreas Huber078cfcf2011-09-15 12:25:04 -0700254 } else {
Steve Block3856b092011-10-20 11:56:00 +0100255 ALOGV("audio queue has %d frames left to play",
Andreas Huber078cfcf2011-09-15 12:25:04 -0700256 mAudioSink->frameCount() - numFramesAvailableToWrite);
257 }
258#endif
259
260 size_t numBytesAvailableToWrite =
261 numFramesAvailableToWrite * mAudioSink->frameSize();
262
263 while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
Andreas Huberc92fd242011-08-16 13:48:44 -0700264 QueueEntry *entry = &*mAudioQueue.begin();
265
266 if (entry->mBuffer == NULL) {
267 // EOS
268
269 notifyEOS(true /* audio */, entry->mFinalResult);
270
271 mAudioQueue.erase(mAudioQueue.begin());
272 entry = NULL;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700273 return false;
Eric Laurent9b7d9502011-03-21 11:49:00 -0700274 }
275
Andreas Huberf9334412010-12-15 15:17:42 -0800276 if (entry->mOffset == 0) {
277 int64_t mediaTimeUs;
278 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
279
Steve Block3856b092011-10-20 11:56:00 +0100280 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
Andreas Huberf9334412010-12-15 15:17:42 -0800281
282 mAnchorTimeMediaUs = mediaTimeUs;
283
284 uint32_t numFramesPlayed;
285 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
286
287 uint32_t numFramesPendingPlayout =
288 mNumFramesWritten - numFramesPlayed;
289
290 int64_t realTimeOffsetUs =
291 (mAudioSink->latency() / 2 /* XXX */
292 + numFramesPendingPlayout
293 * mAudioSink->msecsPerFrame()) * 1000ll;
294
Steve Blockdf64d152012-01-04 20:05:49 +0000295 // ALOGI("realTimeOffsetUs = %lld us", realTimeOffsetUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800296
297 mAnchorTimeRealUs =
298 ALooper::GetNowUs() + realTimeOffsetUs;
299 }
300
301 size_t copy = entry->mBuffer->size() - entry->mOffset;
302 if (copy > numBytesAvailableToWrite) {
303 copy = numBytesAvailableToWrite;
304 }
305
306 CHECK_EQ(mAudioSink->write(
307 entry->mBuffer->data() + entry->mOffset, copy),
308 (ssize_t)copy);
309
310 entry->mOffset += copy;
311 if (entry->mOffset == entry->mBuffer->size()) {
312 entry->mNotifyConsumed->post();
313 mAudioQueue.erase(mAudioQueue.begin());
Eric Laurent9b7d9502011-03-21 11:49:00 -0700314
Andreas Huberf9334412010-12-15 15:17:42 -0800315 entry = NULL;
316 }
317
Andreas Huber078cfcf2011-09-15 12:25:04 -0700318 numBytesAvailableToWrite -= copy;
319 size_t copiedFrames = copy / mAudioSink->frameSize();
320 mNumFramesWritten += copiedFrames;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700321
322 notifyIfMediaRenderingStarted();
Andreas Huberf9334412010-12-15 15:17:42 -0800323 }
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800324
325 notifyPosition();
Andreas Huber078cfcf2011-09-15 12:25:04 -0700326
327 return !mAudioQueue.empty();
Andreas Huberf9334412010-12-15 15:17:42 -0800328}
329
330void NuPlayer::Renderer::postDrainVideoQueue() {
Andreas Huberb4082222011-01-20 15:23:04 -0800331 if (mDrainVideoQueuePending || mSyncQueues || mPaused) {
Andreas Huberf9334412010-12-15 15:17:42 -0800332 return;
333 }
334
335 if (mVideoQueue.empty()) {
336 return;
337 }
338
339 QueueEntry &entry = *mVideoQueue.begin();
340
341 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
342 msg->setInt32("generation", mVideoQueueGeneration);
343
344 int64_t delayUs;
345
346 if (entry.mBuffer == NULL) {
347 // EOS doesn't carry a timestamp.
348 delayUs = 0;
Andreas Huberd5e56232013-03-12 11:01:43 -0700349 } else if (mFlags & FLAG_REAL_TIME) {
350 int64_t mediaTimeUs;
351 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
352
353 delayUs = mediaTimeUs - ALooper::GetNowUs();
Andreas Huberf9334412010-12-15 15:17:42 -0800354 } else {
355 int64_t mediaTimeUs;
356 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
357
358 if (mAnchorTimeMediaUs < 0) {
359 delayUs = 0;
360
Andreas Huber3831a062010-12-21 10:22:33 -0800361 if (!mHasAudio) {
Andreas Huberf9334412010-12-15 15:17:42 -0800362 mAnchorTimeMediaUs = mediaTimeUs;
363 mAnchorTimeRealUs = ALooper::GetNowUs();
364 }
365 } else {
366 int64_t realTimeUs =
367 (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs;
368
369 delayUs = realTimeUs - ALooper::GetNowUs();
370 }
371 }
372
373 msg->post(delayUs);
374
375 mDrainVideoQueuePending = true;
376}
377
378void NuPlayer::Renderer::onDrainVideoQueue() {
379 if (mVideoQueue.empty()) {
380 return;
381 }
382
383 QueueEntry *entry = &*mVideoQueue.begin();
384
385 if (entry->mBuffer == NULL) {
386 // EOS
387
Andreas Huberc92fd242011-08-16 13:48:44 -0700388 notifyEOS(false /* audio */, entry->mFinalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800389
390 mVideoQueue.erase(mVideoQueue.begin());
391 entry = NULL;
Andreas Huber3fe62152011-09-16 15:09:22 -0700392
393 mVideoLateByUs = 0ll;
394
395 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800396 return;
397 }
398
Andreas Huberd5e56232013-03-12 11:01:43 -0700399 int64_t realTimeUs;
400 if (mFlags & FLAG_REAL_TIME) {
401 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
402 } else {
403 int64_t mediaTimeUs;
404 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
Andreas Huberf9334412010-12-15 15:17:42 -0800405
Andreas Huberd5e56232013-03-12 11:01:43 -0700406 realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
407 }
408
Andreas Huber3fe62152011-09-16 15:09:22 -0700409 mVideoLateByUs = ALooper::GetNowUs() - realTimeUs;
Andreas Huber3fe62152011-09-16 15:09:22 -0700410 bool tooLate = (mVideoLateByUs > 40000);
411
412 if (tooLate) {
Andreas Huberafed0e12011-09-20 15:39:58 -0700413 ALOGV("video late by %lld us (%.2f secs)",
414 mVideoLateByUs, mVideoLateByUs / 1E6);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700415 } else {
Oscar Rydhéd6074f02013-10-15 09:54:08 +0200416 ALOGV("rendering video at media time %.2f secs",
417 (mFlags & FLAG_REAL_TIME ? realTimeUs :
418 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700419 }
Andreas Huberf9334412010-12-15 15:17:42 -0800420
Glenn Kasten683525b2011-11-04 18:05:35 -0700421 entry->mNotifyConsumed->setInt32("render", !tooLate);
Andreas Huberf9334412010-12-15 15:17:42 -0800422 entry->mNotifyConsumed->post();
423 mVideoQueue.erase(mVideoQueue.begin());
424 entry = NULL;
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800425
James Dongf57b4ea2012-07-20 13:38:36 -0700426 if (!mVideoRenderingStarted) {
427 mVideoRenderingStarted = true;
428 notifyVideoRenderingStart();
429 }
430
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700431 notifyIfMediaRenderingStarted();
432
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800433 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800434}
435
James Dongf57b4ea2012-07-20 13:38:36 -0700436void NuPlayer::Renderer::notifyVideoRenderingStart() {
437 sp<AMessage> notify = mNotify->dup();
438 notify->setInt32("what", kWhatVideoRenderingStart);
439 notify->post();
440}
441
Andreas Huberc92fd242011-08-16 13:48:44 -0700442void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) {
Andreas Huberf9334412010-12-15 15:17:42 -0800443 sp<AMessage> notify = mNotify->dup();
444 notify->setInt32("what", kWhatEOS);
445 notify->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huberc92fd242011-08-16 13:48:44 -0700446 notify->setInt32("finalResult", finalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800447 notify->post();
448}
449
450void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
451 int32_t audio;
452 CHECK(msg->findInt32("audio", &audio));
453
Andreas Huberbc7f5b22011-01-21 10:15:23 -0800454 if (audio) {
455 mHasAudio = true;
456 } else {
457 mHasVideo = true;
458 }
459
Andreas Huberf9334412010-12-15 15:17:42 -0800460 if (dropBufferWhileFlushing(audio, msg)) {
461 return;
462 }
463
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800464 sp<ABuffer> buffer;
465 CHECK(msg->findBuffer("buffer", &buffer));
Andreas Huberf9334412010-12-15 15:17:42 -0800466
467 sp<AMessage> notifyConsumed;
468 CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
469
470 QueueEntry entry;
471 entry.mBuffer = buffer;
472 entry.mNotifyConsumed = notifyConsumed;
473 entry.mOffset = 0;
474 entry.mFinalResult = OK;
475
476 if (audio) {
477 mAudioQueue.push_back(entry);
478 postDrainAudioQueue();
479 } else {
480 mVideoQueue.push_back(entry);
481 postDrainVideoQueue();
482 }
483
Andreas Hubercb67cd12011-08-26 16:02:19 -0700484 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
485 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800486 }
Andreas Hubercb67cd12011-08-26 16:02:19 -0700487
488 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
489 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
490
491 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
492 // EOS signalled on either queue.
493 syncQueuesDone();
494 return;
495 }
496
497 int64_t firstAudioTimeUs;
498 int64_t firstVideoTimeUs;
499 CHECK(firstAudioBuffer->meta()
500 ->findInt64("timeUs", &firstAudioTimeUs));
501 CHECK(firstVideoBuffer->meta()
502 ->findInt64("timeUs", &firstVideoTimeUs));
503
504 int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
505
Steve Block3856b092011-10-20 11:56:00 +0100506 ALOGV("queueDiff = %.2f secs", diff / 1E6);
Andreas Hubercb67cd12011-08-26 16:02:19 -0700507
508 if (diff > 100000ll) {
509 // Audio data starts More than 0.1 secs before video.
510 // Drop some audio.
511
512 (*mAudioQueue.begin()).mNotifyConsumed->post();
513 mAudioQueue.erase(mAudioQueue.begin());
514 return;
515 }
516
517 syncQueuesDone();
Andreas Huberf9334412010-12-15 15:17:42 -0800518}
519
520void NuPlayer::Renderer::syncQueuesDone() {
521 if (!mSyncQueues) {
522 return;
523 }
524
525 mSyncQueues = false;
526
527 if (!mAudioQueue.empty()) {
528 postDrainAudioQueue();
529 }
530
531 if (!mVideoQueue.empty()) {
532 postDrainVideoQueue();
533 }
534}
535
536void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {
537 int32_t audio;
538 CHECK(msg->findInt32("audio", &audio));
539
540 if (dropBufferWhileFlushing(audio, msg)) {
541 return;
542 }
543
544 int32_t finalResult;
545 CHECK(msg->findInt32("finalResult", &finalResult));
546
547 QueueEntry entry;
548 entry.mOffset = 0;
549 entry.mFinalResult = finalResult;
550
551 if (audio) {
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100552 if (mAudioQueue.empty() && mSyncQueues) {
553 syncQueuesDone();
554 }
Andreas Huberf9334412010-12-15 15:17:42 -0800555 mAudioQueue.push_back(entry);
556 postDrainAudioQueue();
557 } else {
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100558 if (mVideoQueue.empty() && mSyncQueues) {
559 syncQueuesDone();
560 }
Andreas Huberf9334412010-12-15 15:17:42 -0800561 mVideoQueue.push_back(entry);
562 postDrainVideoQueue();
563 }
564}
565
566void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
567 int32_t audio;
568 CHECK(msg->findInt32("audio", &audio));
569
570 // If we're currently syncing the queues, i.e. dropping audio while
571 // aligning the first audio/video buffer times and only one of the
572 // two queues has data, we may starve that queue by not requesting
573 // more buffers from the decoder. If the other source then encounters
574 // a discontinuity that leads to flushing, we'll never find the
575 // corresponding discontinuity on the other queue.
576 // Therefore we'll stop syncing the queues if at least one of them
577 // is flushed.
578 syncQueuesDone();
579
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700580 ALOGV("flushing %s", audio ? "audio" : "video");
Andreas Huberf9334412010-12-15 15:17:42 -0800581 if (audio) {
582 flushQueue(&mAudioQueue);
583
584 Mutex::Autolock autoLock(mFlushLock);
585 mFlushingAudio = false;
586
587 mDrainAudioQueuePending = false;
588 ++mAudioQueueGeneration;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700589
590 prepareForMediaRenderingStart();
Andreas Huberf9334412010-12-15 15:17:42 -0800591 } else {
592 flushQueue(&mVideoQueue);
593
594 Mutex::Autolock autoLock(mFlushLock);
595 mFlushingVideo = false;
596
597 mDrainVideoQueuePending = false;
598 ++mVideoQueueGeneration;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700599
600 prepareForMediaRenderingStart();
Andreas Huberf9334412010-12-15 15:17:42 -0800601 }
602
603 notifyFlushComplete(audio);
604}
605
606void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) {
607 while (!queue->empty()) {
608 QueueEntry *entry = &*queue->begin();
609
610 if (entry->mBuffer != NULL) {
611 entry->mNotifyConsumed->post();
612 }
613
614 queue->erase(queue->begin());
615 entry = NULL;
616 }
617}
618
619void NuPlayer::Renderer::notifyFlushComplete(bool audio) {
620 sp<AMessage> notify = mNotify->dup();
621 notify->setInt32("what", kWhatFlushComplete);
622 notify->setInt32("audio", static_cast<int32_t>(audio));
623 notify->post();
624}
625
626bool NuPlayer::Renderer::dropBufferWhileFlushing(
627 bool audio, const sp<AMessage> &msg) {
628 bool flushing = false;
629
630 {
631 Mutex::Autolock autoLock(mFlushLock);
632 if (audio) {
633 flushing = mFlushingAudio;
634 } else {
635 flushing = mFlushingVideo;
636 }
637 }
638
639 if (!flushing) {
640 return false;
641 }
642
643 sp<AMessage> notifyConsumed;
644 if (msg->findMessage("notifyConsumed", &notifyConsumed)) {
645 notifyConsumed->post();
646 }
647
648 return true;
649}
650
Andreas Huber3831a062010-12-21 10:22:33 -0800651void NuPlayer::Renderer::onAudioSinkChanged() {
652 CHECK(!mDrainAudioQueuePending);
653 mNumFramesWritten = 0;
Marco Nelissen4110c102012-03-29 09:31:28 -0700654 uint32_t written;
655 if (mAudioSink->getFramesWritten(&written) == OK) {
656 mNumFramesWritten = written;
657 }
Andreas Huber3831a062010-12-21 10:22:33 -0800658}
659
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800660void NuPlayer::Renderer::notifyPosition() {
661 if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) {
662 return;
663 }
664
665 int64_t nowUs = ALooper::GetNowUs();
Andreas Huber714aa7b2011-09-13 08:28:38 -0700666
667 if (mLastPositionUpdateUs >= 0
668 && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
669 return;
670 }
671 mLastPositionUpdateUs = nowUs;
672
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800673 int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
674
675 sp<AMessage> notify = mNotify->dup();
676 notify->setInt32("what", kWhatPosition);
677 notify->setInt64("positionUs", positionUs);
Andreas Huber3fe62152011-09-16 15:09:22 -0700678 notify->setInt64("videoLateByUs", mVideoLateByUs);
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800679 notify->post();
680}
681
Andreas Huberb4082222011-01-20 15:23:04 -0800682void NuPlayer::Renderer::onPause() {
683 CHECK(!mPaused);
684
685 mDrainAudioQueuePending = false;
686 ++mAudioQueueGeneration;
687
688 mDrainVideoQueuePending = false;
689 ++mVideoQueueGeneration;
690
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700691 prepareForMediaRenderingStart();
692
Andreas Huberb4082222011-01-20 15:23:04 -0800693 if (mHasAudio) {
694 mAudioSink->pause();
695 }
696
Andreas Huberea9d51b2011-11-30 09:53:40 -0800697 ALOGV("now paused audio queue has %d entries, video has %d entries",
698 mAudioQueue.size(), mVideoQueue.size());
Andreas Huberb58ce9f2011-11-28 16:27:35 -0800699
Andreas Huberb4082222011-01-20 15:23:04 -0800700 mPaused = true;
701}
702
703void NuPlayer::Renderer::onResume() {
Andreas Huberb58ce9f2011-11-28 16:27:35 -0800704 if (!mPaused) {
705 return;
706 }
Andreas Huberb4082222011-01-20 15:23:04 -0800707
708 if (mHasAudio) {
709 mAudioSink->start();
710 }
711
712 mPaused = false;
713
714 if (!mAudioQueue.empty()) {
715 postDrainAudioQueue();
716 }
717
718 if (!mVideoQueue.empty()) {
719 postDrainVideoQueue();
720 }
721}
722
Andreas Huberf9334412010-12-15 15:17:42 -0800723} // namespace android
724