blob: 8592ec2499eeec5883ff9c1d78a6c779771bdd80 [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
Andreas Huber714aa7b2011-09-13 08:28:38 -070033// static
34const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
35
Andreas Huberf9334412010-12-15 15:17:42 -080036NuPlayer::Renderer::Renderer(
37 const sp<MediaPlayerBase::AudioSink> &sink,
Andreas Huberd5e56232013-03-12 11:01:43 -070038 const sp<AMessage> &notify,
39 uint32_t flags)
Andreas Huberf9334412010-12-15 15:17:42 -080040 : mAudioSink(sink),
41 mNotify(notify),
Andreas Huberd5e56232013-03-12 11:01:43 -070042 mFlags(flags),
Andreas Huberf9334412010-12-15 15:17:42 -080043 mNumFramesWritten(0),
44 mDrainAudioQueuePending(false),
45 mDrainVideoQueuePending(false),
46 mAudioQueueGeneration(0),
47 mVideoQueueGeneration(0),
Wei Jiabc2fb722014-07-08 16:37:57 -070048 mFirstAudioTimeUs(-1),
Andreas Huberf9334412010-12-15 15:17:42 -080049 mAnchorTimeMediaUs(-1),
50 mAnchorTimeRealUs(-1),
51 mFlushingAudio(false),
52 mFlushingVideo(false),
Andreas Huberbc7f5b22011-01-21 10:15:23 -080053 mHasAudio(false),
54 mHasVideo(false),
55 mSyncQueues(false),
Andreas Huber714aa7b2011-09-13 08:28:38 -070056 mPaused(false),
James Dongf57b4ea2012-07-20 13:38:36 -070057 mVideoRenderingStarted(false),
Lajos Molnarcbaffcf2013-08-14 18:30:38 -070058 mVideoRenderingStartGeneration(0),
59 mAudioRenderingStartGeneration(0),
Andreas Huber3fe62152011-09-16 15:09:22 -070060 mLastPositionUpdateUs(-1ll),
61 mVideoLateByUs(0ll) {
Andreas Huberf9334412010-12-15 15:17:42 -080062}
63
64NuPlayer::Renderer::~Renderer() {
Wei Jiabc2fb722014-07-08 16:37:57 -070065 if (offloadingAudio()) {
66 mAudioSink->stop();
67 mAudioSink->flush();
68 mAudioSink->close();
69 }
Andreas Huberf9334412010-12-15 15:17:42 -080070}
71
72void NuPlayer::Renderer::queueBuffer(
73 bool audio,
74 const sp<ABuffer> &buffer,
75 const sp<AMessage> &notifyConsumed) {
76 sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
77 msg->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huber2d8bedd2012-02-21 14:38:23 -080078 msg->setBuffer("buffer", buffer);
Andreas Huberf9334412010-12-15 15:17:42 -080079 msg->setMessage("notifyConsumed", notifyConsumed);
80 msg->post();
81}
82
83void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
84 CHECK_NE(finalResult, (status_t)OK);
85
86 sp<AMessage> msg = new AMessage(kWhatQueueEOS, id());
87 msg->setInt32("audio", static_cast<int32_t>(audio));
88 msg->setInt32("finalResult", finalResult);
89 msg->post();
90}
91
92void NuPlayer::Renderer::flush(bool audio) {
93 {
94 Mutex::Autolock autoLock(mFlushLock);
95 if (audio) {
96 CHECK(!mFlushingAudio);
97 mFlushingAudio = true;
98 } else {
99 CHECK(!mFlushingVideo);
100 mFlushingVideo = true;
101 }
102 }
103
104 sp<AMessage> msg = new AMessage(kWhatFlush, id());
105 msg->setInt32("audio", static_cast<int32_t>(audio));
106 msg->post();
107}
108
109void NuPlayer::Renderer::signalTimeDiscontinuity() {
Wei Jiabc2fb722014-07-08 16:37:57 -0700110 Mutex::Autolock autoLock(mLock);
Andreas Huber14f76722013-01-15 09:04:18 -0800111 // CHECK(mAudioQueue.empty());
112 // CHECK(mVideoQueue.empty());
Andreas Huberf9334412010-12-15 15:17:42 -0800113 mAnchorTimeMediaUs = -1;
114 mAnchorTimeRealUs = -1;
Andreas Huber14f76722013-01-15 09:04:18 -0800115 mSyncQueues = false;
Andreas Huberf9334412010-12-15 15:17:42 -0800116}
117
Andreas Huberb4082222011-01-20 15:23:04 -0800118void NuPlayer::Renderer::pause() {
119 (new AMessage(kWhatPause, id()))->post();
120}
121
122void NuPlayer::Renderer::resume() {
123 (new AMessage(kWhatResume, id()))->post();
124}
125
Andreas Huberf9334412010-12-15 15:17:42 -0800126void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
127 switch (msg->what()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700128 case kWhatStopAudioSink:
129 {
130 mAudioSink->stop();
131 break;
132 }
133
Andreas Huberf9334412010-12-15 15:17:42 -0800134 case kWhatDrainAudioQueue:
135 {
136 int32_t generation;
137 CHECK(msg->findInt32("generation", &generation));
138 if (generation != mAudioQueueGeneration) {
139 break;
140 }
141
142 mDrainAudioQueuePending = false;
143
Andreas Huber078cfcf2011-09-15 12:25:04 -0700144 if (onDrainAudioQueue()) {
145 uint32_t numFramesPlayed;
146 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
147 (status_t)OK);
Andreas Huberf9334412010-12-15 15:17:42 -0800148
Andreas Huber078cfcf2011-09-15 12:25:04 -0700149 uint32_t numFramesPendingPlayout =
150 mNumFramesWritten - numFramesPlayed;
151
152 // This is how long the audio sink will have data to
153 // play back.
154 int64_t delayUs =
155 mAudioSink->msecsPerFrame()
156 * numFramesPendingPlayout * 1000ll;
157
158 // Let's give it more data after about half that time
159 // has elapsed.
Wei Jiabc2fb722014-07-08 16:37:57 -0700160 // kWhatDrainAudioQueue is used for non-offloading mode,
161 // and mLock is used only for offloading mode. Therefore,
162 // no need to acquire mLock here.
163 postDrainAudioQueue_l(delayUs / 2);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700164 }
Andreas Huberf9334412010-12-15 15:17:42 -0800165 break;
166 }
167
168 case kWhatDrainVideoQueue:
169 {
170 int32_t generation;
171 CHECK(msg->findInt32("generation", &generation));
172 if (generation != mVideoQueueGeneration) {
173 break;
174 }
175
176 mDrainVideoQueuePending = false;
177
178 onDrainVideoQueue();
179
180 postDrainVideoQueue();
181 break;
182 }
183
184 case kWhatQueueBuffer:
185 {
186 onQueueBuffer(msg);
187 break;
188 }
189
190 case kWhatQueueEOS:
191 {
192 onQueueEOS(msg);
193 break;
194 }
195
196 case kWhatFlush:
197 {
198 onFlush(msg);
199 break;
200 }
201
Andreas Huber3831a062010-12-21 10:22:33 -0800202 case kWhatAudioSinkChanged:
203 {
204 onAudioSinkChanged();
205 break;
206 }
207
Wei Jiabc2fb722014-07-08 16:37:57 -0700208 case kWhatDisableOffloadAudio:
209 {
210 onDisableOffloadAudio();
211 break;
212 }
213
Andreas Huberb4082222011-01-20 15:23:04 -0800214 case kWhatPause:
215 {
216 onPause();
217 break;
218 }
219
220 case kWhatResume:
221 {
222 onResume();
223 break;
224 }
225
Andreas Huberf9334412010-12-15 15:17:42 -0800226 default:
227 TRESPASS();
228 break;
229 }
230}
231
Wei Jiabc2fb722014-07-08 16:37:57 -0700232void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
233 if (mDrainAudioQueuePending || mSyncQueues || mPaused
234 || offloadingAudio()) {
Andreas Huberf9334412010-12-15 15:17:42 -0800235 return;
236 }
237
238 if (mAudioQueue.empty()) {
239 return;
240 }
241
242 mDrainAudioQueuePending = true;
243 sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
244 msg->setInt32("generation", mAudioQueueGeneration);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700245 msg->post(delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800246}
247
Andreas Huber3831a062010-12-21 10:22:33 -0800248void NuPlayer::Renderer::signalAudioSinkChanged() {
249 (new AMessage(kWhatAudioSinkChanged, id()))->post();
250}
251
Wei Jiabc2fb722014-07-08 16:37:57 -0700252void NuPlayer::Renderer::signalDisableOffloadAudio() {
253 (new AMessage(kWhatDisableOffloadAudio, id()))->post();
254}
255
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700256void NuPlayer::Renderer::prepareForMediaRenderingStart() {
257 mAudioRenderingStartGeneration = mAudioQueueGeneration;
258 mVideoRenderingStartGeneration = mVideoQueueGeneration;
259}
260
261void NuPlayer::Renderer::notifyIfMediaRenderingStarted() {
262 if (mVideoRenderingStartGeneration == mVideoQueueGeneration &&
263 mAudioRenderingStartGeneration == mAudioQueueGeneration) {
264 mVideoRenderingStartGeneration = -1;
265 mAudioRenderingStartGeneration = -1;
266
267 sp<AMessage> notify = mNotify->dup();
268 notify->setInt32("what", kWhatMediaRenderingStart);
269 notify->post();
270 }
271}
272
Wei Jiabc2fb722014-07-08 16:37:57 -0700273// static
274size_t NuPlayer::Renderer::AudioSinkCallback(
275 MediaPlayerBase::AudioSink * /* audioSink */,
276 void *buffer,
277 size_t size,
278 void *cookie,
279 MediaPlayerBase::AudioSink::cb_event_t event) {
280 NuPlayer::Renderer *me = (NuPlayer::Renderer *)cookie;
281
282 switch (event) {
283 case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
284 {
285 return me->fillAudioBuffer(buffer, size);
286 break;
287 }
288
289 case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
290 {
291 me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
292 break;
293 }
294
295 case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
296 {
297 // TODO: send this to player.
298 break;
299 }
300 }
301
302 return 0;
303}
304
305size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
306 Mutex::Autolock autoLock(mLock);
307
308 if (!offloadingAudio()) {
309 return 0;
310 }
311
312 bool hasEOS = false;
313
314 size_t sizeCopied = 0;
315 while (sizeCopied < size && !mAudioQueue.empty()) {
316 QueueEntry *entry = &*mAudioQueue.begin();
317
318 if (entry->mBuffer == NULL) { // EOS
319 hasEOS = true;
320 mAudioQueue.erase(mAudioQueue.begin());
321 entry = NULL;
322 break;
323 }
324
325 if (entry->mOffset == 0) {
326 int64_t mediaTimeUs;
327 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
328 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
329 if (mFirstAudioTimeUs == -1) {
330 mFirstAudioTimeUs = mediaTimeUs;
331 }
332 mAnchorTimeMediaUs = mediaTimeUs;
333
334 uint32_t numFramesPlayed;
335 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
336
337 // TODO: figure out how to calculate initial latency.
338 // Otherwise, the initial time is not correct till the first sample
339 // is played.
340 mAnchorTimeMediaUs = mFirstAudioTimeUs
341 + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll;
342 mAnchorTimeRealUs = ALooper::GetNowUs();
343 }
344
345 size_t copy = entry->mBuffer->size() - entry->mOffset;
346 size_t sizeRemaining = size - sizeCopied;
347 if (copy > sizeRemaining) {
348 copy = sizeRemaining;
349 }
350
351 memcpy((char *)buffer + sizeCopied,
352 entry->mBuffer->data() + entry->mOffset,
353 copy);
354
355 entry->mOffset += copy;
356 if (entry->mOffset == entry->mBuffer->size()) {
357 entry->mNotifyConsumed->post();
358 mAudioQueue.erase(mAudioQueue.begin());
359 entry = NULL;
360 }
361 sizeCopied += copy;
362 notifyIfMediaRenderingStarted();
363 }
364
365 if (sizeCopied != 0) {
366 notifyPosition();
367 }
368
369 if (hasEOS) {
370 (new AMessage(kWhatStopAudioSink, id()))->post();
371 }
372
373 return sizeCopied;
374}
375
Andreas Huber078cfcf2011-09-15 12:25:04 -0700376bool NuPlayer::Renderer::onDrainAudioQueue() {
377 uint32_t numFramesPlayed;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700378 if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
379 return false;
380 }
Andreas Huberc92fd242011-08-16 13:48:44 -0700381
Andreas Huber078cfcf2011-09-15 12:25:04 -0700382 ssize_t numFramesAvailableToWrite =
383 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
384
385#if 0
386 if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
Steve Blockdf64d152012-01-04 20:05:49 +0000387 ALOGI("audio sink underrun");
Andreas Huber078cfcf2011-09-15 12:25:04 -0700388 } else {
Steve Block3856b092011-10-20 11:56:00 +0100389 ALOGV("audio queue has %d frames left to play",
Andreas Huber078cfcf2011-09-15 12:25:04 -0700390 mAudioSink->frameCount() - numFramesAvailableToWrite);
391 }
392#endif
393
394 size_t numBytesAvailableToWrite =
395 numFramesAvailableToWrite * mAudioSink->frameSize();
396
397 while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
Andreas Huberc92fd242011-08-16 13:48:44 -0700398 QueueEntry *entry = &*mAudioQueue.begin();
399
400 if (entry->mBuffer == NULL) {
401 // EOS
402
403 notifyEOS(true /* audio */, entry->mFinalResult);
404
405 mAudioQueue.erase(mAudioQueue.begin());
406 entry = NULL;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700407 return false;
Eric Laurent9b7d9502011-03-21 11:49:00 -0700408 }
409
Andreas Huberf9334412010-12-15 15:17:42 -0800410 if (entry->mOffset == 0) {
411 int64_t mediaTimeUs;
412 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
413
Steve Block3856b092011-10-20 11:56:00 +0100414 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
Andreas Huberf9334412010-12-15 15:17:42 -0800415
416 mAnchorTimeMediaUs = mediaTimeUs;
417
418 uint32_t numFramesPlayed;
419 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
420
421 uint32_t numFramesPendingPlayout =
422 mNumFramesWritten - numFramesPlayed;
423
424 int64_t realTimeOffsetUs =
425 (mAudioSink->latency() / 2 /* XXX */
426 + numFramesPendingPlayout
427 * mAudioSink->msecsPerFrame()) * 1000ll;
428
Steve Blockdf64d152012-01-04 20:05:49 +0000429 // ALOGI("realTimeOffsetUs = %lld us", realTimeOffsetUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800430
431 mAnchorTimeRealUs =
432 ALooper::GetNowUs() + realTimeOffsetUs;
433 }
434
435 size_t copy = entry->mBuffer->size() - entry->mOffset;
436 if (copy > numBytesAvailableToWrite) {
437 copy = numBytesAvailableToWrite;
438 }
439
440 CHECK_EQ(mAudioSink->write(
441 entry->mBuffer->data() + entry->mOffset, copy),
442 (ssize_t)copy);
443
444 entry->mOffset += copy;
445 if (entry->mOffset == entry->mBuffer->size()) {
446 entry->mNotifyConsumed->post();
447 mAudioQueue.erase(mAudioQueue.begin());
Eric Laurent9b7d9502011-03-21 11:49:00 -0700448
Andreas Huberf9334412010-12-15 15:17:42 -0800449 entry = NULL;
450 }
451
Andreas Huber078cfcf2011-09-15 12:25:04 -0700452 numBytesAvailableToWrite -= copy;
453 size_t copiedFrames = copy / mAudioSink->frameSize();
454 mNumFramesWritten += copiedFrames;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700455
456 notifyIfMediaRenderingStarted();
Andreas Huberf9334412010-12-15 15:17:42 -0800457 }
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800458
459 notifyPosition();
Andreas Huber078cfcf2011-09-15 12:25:04 -0700460
461 return !mAudioQueue.empty();
Andreas Huberf9334412010-12-15 15:17:42 -0800462}
463
464void NuPlayer::Renderer::postDrainVideoQueue() {
Andreas Huberb4082222011-01-20 15:23:04 -0800465 if (mDrainVideoQueuePending || mSyncQueues || mPaused) {
Andreas Huberf9334412010-12-15 15:17:42 -0800466 return;
467 }
468
469 if (mVideoQueue.empty()) {
470 return;
471 }
472
473 QueueEntry &entry = *mVideoQueue.begin();
474
475 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
476 msg->setInt32("generation", mVideoQueueGeneration);
477
478 int64_t delayUs;
479
480 if (entry.mBuffer == NULL) {
481 // EOS doesn't carry a timestamp.
482 delayUs = 0;
Andreas Huberd5e56232013-03-12 11:01:43 -0700483 } else if (mFlags & FLAG_REAL_TIME) {
484 int64_t mediaTimeUs;
485 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
486
487 delayUs = mediaTimeUs - ALooper::GetNowUs();
Andreas Huberf9334412010-12-15 15:17:42 -0800488 } else {
489 int64_t mediaTimeUs;
490 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
491
492 if (mAnchorTimeMediaUs < 0) {
493 delayUs = 0;
494
Andreas Huber3831a062010-12-21 10:22:33 -0800495 if (!mHasAudio) {
Andreas Huberf9334412010-12-15 15:17:42 -0800496 mAnchorTimeMediaUs = mediaTimeUs;
497 mAnchorTimeRealUs = ALooper::GetNowUs();
498 }
499 } else {
500 int64_t realTimeUs =
501 (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs;
502
503 delayUs = realTimeUs - ALooper::GetNowUs();
504 }
505 }
506
Lajos Molnar09524832014-07-17 14:29:51 -0700507 ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800508 msg->post(delayUs);
509
510 mDrainVideoQueuePending = true;
511}
512
513void NuPlayer::Renderer::onDrainVideoQueue() {
514 if (mVideoQueue.empty()) {
515 return;
516 }
517
518 QueueEntry *entry = &*mVideoQueue.begin();
519
520 if (entry->mBuffer == NULL) {
521 // EOS
522
Andreas Huberc92fd242011-08-16 13:48:44 -0700523 notifyEOS(false /* audio */, entry->mFinalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800524
525 mVideoQueue.erase(mVideoQueue.begin());
526 entry = NULL;
Andreas Huber3fe62152011-09-16 15:09:22 -0700527
528 mVideoLateByUs = 0ll;
529
530 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800531 return;
532 }
533
Andreas Huberd5e56232013-03-12 11:01:43 -0700534 int64_t realTimeUs;
535 if (mFlags & FLAG_REAL_TIME) {
536 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
537 } else {
538 int64_t mediaTimeUs;
539 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
Andreas Huberf9334412010-12-15 15:17:42 -0800540
Andreas Huberd5e56232013-03-12 11:01:43 -0700541 realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
542 }
543
Andreas Huber3fe62152011-09-16 15:09:22 -0700544 mVideoLateByUs = ALooper::GetNowUs() - realTimeUs;
Andreas Huber3fe62152011-09-16 15:09:22 -0700545 bool tooLate = (mVideoLateByUs > 40000);
546
547 if (tooLate) {
Andreas Huberafed0e12011-09-20 15:39:58 -0700548 ALOGV("video late by %lld us (%.2f secs)",
549 mVideoLateByUs, mVideoLateByUs / 1E6);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700550 } else {
Oscar Rydhéd6074f02013-10-15 09:54:08 +0200551 ALOGV("rendering video at media time %.2f secs",
552 (mFlags & FLAG_REAL_TIME ? realTimeUs :
553 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700554 }
Andreas Huberf9334412010-12-15 15:17:42 -0800555
Glenn Kasten683525b2011-11-04 18:05:35 -0700556 entry->mNotifyConsumed->setInt32("render", !tooLate);
Andreas Huberf9334412010-12-15 15:17:42 -0800557 entry->mNotifyConsumed->post();
558 mVideoQueue.erase(mVideoQueue.begin());
559 entry = NULL;
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800560
James Dongf57b4ea2012-07-20 13:38:36 -0700561 if (!mVideoRenderingStarted) {
562 mVideoRenderingStarted = true;
563 notifyVideoRenderingStart();
564 }
565
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700566 notifyIfMediaRenderingStarted();
567
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800568 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800569}
570
James Dongf57b4ea2012-07-20 13:38:36 -0700571void NuPlayer::Renderer::notifyVideoRenderingStart() {
572 sp<AMessage> notify = mNotify->dup();
573 notify->setInt32("what", kWhatVideoRenderingStart);
574 notify->post();
575}
576
Andreas Huberc92fd242011-08-16 13:48:44 -0700577void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) {
Andreas Huberf9334412010-12-15 15:17:42 -0800578 sp<AMessage> notify = mNotify->dup();
579 notify->setInt32("what", kWhatEOS);
580 notify->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huberc92fd242011-08-16 13:48:44 -0700581 notify->setInt32("finalResult", finalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800582 notify->post();
583}
584
585void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
586 int32_t audio;
587 CHECK(msg->findInt32("audio", &audio));
588
Andreas Huberbc7f5b22011-01-21 10:15:23 -0800589 if (audio) {
590 mHasAudio = true;
591 } else {
592 mHasVideo = true;
593 }
594
Andreas Huberf9334412010-12-15 15:17:42 -0800595 if (dropBufferWhileFlushing(audio, msg)) {
596 return;
597 }
598
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800599 sp<ABuffer> buffer;
600 CHECK(msg->findBuffer("buffer", &buffer));
Andreas Huberf9334412010-12-15 15:17:42 -0800601
602 sp<AMessage> notifyConsumed;
603 CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
604
605 QueueEntry entry;
606 entry.mBuffer = buffer;
607 entry.mNotifyConsumed = notifyConsumed;
608 entry.mOffset = 0;
609 entry.mFinalResult = OK;
610
611 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700612 Mutex::Autolock autoLock(mLock);
Andreas Huberf9334412010-12-15 15:17:42 -0800613 mAudioQueue.push_back(entry);
Wei Jiabc2fb722014-07-08 16:37:57 -0700614 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800615 } else {
616 mVideoQueue.push_back(entry);
617 postDrainVideoQueue();
618 }
619
Wei Jiabc2fb722014-07-08 16:37:57 -0700620 Mutex::Autolock autoLock(mLock);
Andreas Hubercb67cd12011-08-26 16:02:19 -0700621 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
622 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800623 }
Andreas Hubercb67cd12011-08-26 16:02:19 -0700624
625 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
626 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
627
628 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
629 // EOS signalled on either queue.
Wei Jiabc2fb722014-07-08 16:37:57 -0700630 syncQueuesDone_l();
Andreas Hubercb67cd12011-08-26 16:02:19 -0700631 return;
632 }
633
634 int64_t firstAudioTimeUs;
635 int64_t firstVideoTimeUs;
636 CHECK(firstAudioBuffer->meta()
637 ->findInt64("timeUs", &firstAudioTimeUs));
638 CHECK(firstVideoBuffer->meta()
639 ->findInt64("timeUs", &firstVideoTimeUs));
640
641 int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
642
Steve Block3856b092011-10-20 11:56:00 +0100643 ALOGV("queueDiff = %.2f secs", diff / 1E6);
Andreas Hubercb67cd12011-08-26 16:02:19 -0700644
645 if (diff > 100000ll) {
646 // Audio data starts More than 0.1 secs before video.
647 // Drop some audio.
648
649 (*mAudioQueue.begin()).mNotifyConsumed->post();
650 mAudioQueue.erase(mAudioQueue.begin());
651 return;
652 }
653
Wei Jiabc2fb722014-07-08 16:37:57 -0700654 syncQueuesDone_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800655}
656
Wei Jiabc2fb722014-07-08 16:37:57 -0700657void NuPlayer::Renderer::syncQueuesDone_l() {
Andreas Huberf9334412010-12-15 15:17:42 -0800658 if (!mSyncQueues) {
659 return;
660 }
661
662 mSyncQueues = false;
663
664 if (!mAudioQueue.empty()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700665 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800666 }
667
668 if (!mVideoQueue.empty()) {
669 postDrainVideoQueue();
670 }
671}
672
673void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {
674 int32_t audio;
675 CHECK(msg->findInt32("audio", &audio));
676
677 if (dropBufferWhileFlushing(audio, msg)) {
678 return;
679 }
680
681 int32_t finalResult;
682 CHECK(msg->findInt32("finalResult", &finalResult));
683
684 QueueEntry entry;
685 entry.mOffset = 0;
686 entry.mFinalResult = finalResult;
687
688 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700689 Mutex::Autolock autoLock(mLock);
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100690 if (mAudioQueue.empty() && mSyncQueues) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700691 syncQueuesDone_l();
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100692 }
Andreas Huberf9334412010-12-15 15:17:42 -0800693 mAudioQueue.push_back(entry);
Wei Jiabc2fb722014-07-08 16:37:57 -0700694 postDrainAudioQueue_l();
Andreas Huberf9334412010-12-15 15:17:42 -0800695 } else {
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100696 if (mVideoQueue.empty() && mSyncQueues) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700697 Mutex::Autolock autoLock(mLock);
698 syncQueuesDone_l();
Roger Jönssonb50e83e2013-01-21 16:26:41 +0100699 }
Andreas Huberf9334412010-12-15 15:17:42 -0800700 mVideoQueue.push_back(entry);
701 postDrainVideoQueue();
702 }
703}
704
705void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
706 int32_t audio;
707 CHECK(msg->findInt32("audio", &audio));
708
709 // If we're currently syncing the queues, i.e. dropping audio while
710 // aligning the first audio/video buffer times and only one of the
711 // two queues has data, we may starve that queue by not requesting
712 // more buffers from the decoder. If the other source then encounters
713 // a discontinuity that leads to flushing, we'll never find the
714 // corresponding discontinuity on the other queue.
715 // Therefore we'll stop syncing the queues if at least one of them
716 // is flushed.
Wei Jiabc2fb722014-07-08 16:37:57 -0700717 {
718 Mutex::Autolock autoLock(mLock);
719 syncQueuesDone_l();
720 }
Andreas Huberf9334412010-12-15 15:17:42 -0800721
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700722 ALOGV("flushing %s", audio ? "audio" : "video");
Andreas Huberf9334412010-12-15 15:17:42 -0800723 if (audio) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700724 {
725 Mutex::Autolock autoLock(mLock);
726 flushQueue(&mAudioQueue);
727 }
Andreas Huberf9334412010-12-15 15:17:42 -0800728
729 Mutex::Autolock autoLock(mFlushLock);
730 mFlushingAudio = false;
731
732 mDrainAudioQueuePending = false;
733 ++mAudioQueueGeneration;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700734
735 prepareForMediaRenderingStart();
Wei Jiabc2fb722014-07-08 16:37:57 -0700736 if (offloadingAudio()) {
737 mFirstAudioTimeUs = -1;
738 mAudioSink->pause();
739 mAudioSink->flush();
740 mAudioSink->start();
741 }
Andreas Huberf9334412010-12-15 15:17:42 -0800742 } else {
743 flushQueue(&mVideoQueue);
744
745 Mutex::Autolock autoLock(mFlushLock);
746 mFlushingVideo = false;
747
748 mDrainVideoQueuePending = false;
749 ++mVideoQueueGeneration;
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700750
751 prepareForMediaRenderingStart();
Andreas Huberf9334412010-12-15 15:17:42 -0800752 }
753
754 notifyFlushComplete(audio);
755}
756
757void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) {
758 while (!queue->empty()) {
759 QueueEntry *entry = &*queue->begin();
760
761 if (entry->mBuffer != NULL) {
762 entry->mNotifyConsumed->post();
763 }
764
765 queue->erase(queue->begin());
766 entry = NULL;
767 }
768}
769
770void NuPlayer::Renderer::notifyFlushComplete(bool audio) {
771 sp<AMessage> notify = mNotify->dup();
772 notify->setInt32("what", kWhatFlushComplete);
773 notify->setInt32("audio", static_cast<int32_t>(audio));
774 notify->post();
775}
776
777bool NuPlayer::Renderer::dropBufferWhileFlushing(
778 bool audio, const sp<AMessage> &msg) {
779 bool flushing = false;
780
781 {
782 Mutex::Autolock autoLock(mFlushLock);
783 if (audio) {
784 flushing = mFlushingAudio;
785 } else {
786 flushing = mFlushingVideo;
787 }
788 }
789
790 if (!flushing) {
791 return false;
792 }
793
794 sp<AMessage> notifyConsumed;
795 if (msg->findMessage("notifyConsumed", &notifyConsumed)) {
796 notifyConsumed->post();
797 }
798
799 return true;
800}
801
Andreas Huber3831a062010-12-21 10:22:33 -0800802void NuPlayer::Renderer::onAudioSinkChanged() {
Wei Jiabc2fb722014-07-08 16:37:57 -0700803 if (offloadingAudio()) {
804 return;
805 }
Andreas Huber3831a062010-12-21 10:22:33 -0800806 CHECK(!mDrainAudioQueuePending);
807 mNumFramesWritten = 0;
Marco Nelissen4110c102012-03-29 09:31:28 -0700808 uint32_t written;
809 if (mAudioSink->getFramesWritten(&written) == OK) {
810 mNumFramesWritten = written;
811 }
Andreas Huber3831a062010-12-21 10:22:33 -0800812}
813
Wei Jiabc2fb722014-07-08 16:37:57 -0700814void NuPlayer::Renderer::onDisableOffloadAudio() {
815 Mutex::Autolock autoLock(mLock);
816 mFlags &= ~FLAG_OFFLOAD_AUDIO;
817}
818
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800819void NuPlayer::Renderer::notifyPosition() {
820 if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) {
821 return;
822 }
823
824 int64_t nowUs = ALooper::GetNowUs();
Andreas Huber714aa7b2011-09-13 08:28:38 -0700825
826 if (mLastPositionUpdateUs >= 0
827 && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
828 return;
829 }
830 mLastPositionUpdateUs = nowUs;
831
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800832 int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
833
834 sp<AMessage> notify = mNotify->dup();
835 notify->setInt32("what", kWhatPosition);
836 notify->setInt64("positionUs", positionUs);
Andreas Huber3fe62152011-09-16 15:09:22 -0700837 notify->setInt64("videoLateByUs", mVideoLateByUs);
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800838 notify->post();
839}
840
Andreas Huberb4082222011-01-20 15:23:04 -0800841void NuPlayer::Renderer::onPause() {
842 CHECK(!mPaused);
843
844 mDrainAudioQueuePending = false;
845 ++mAudioQueueGeneration;
846
847 mDrainVideoQueuePending = false;
848 ++mVideoQueueGeneration;
849
Lajos Molnarcbaffcf2013-08-14 18:30:38 -0700850 prepareForMediaRenderingStart();
851
Andreas Huberb4082222011-01-20 15:23:04 -0800852 if (mHasAudio) {
853 mAudioSink->pause();
854 }
855
Andreas Huberea9d51b2011-11-30 09:53:40 -0800856 ALOGV("now paused audio queue has %d entries, video has %d entries",
857 mAudioQueue.size(), mVideoQueue.size());
Andreas Huberb58ce9f2011-11-28 16:27:35 -0800858
Andreas Huberb4082222011-01-20 15:23:04 -0800859 mPaused = true;
860}
861
862void NuPlayer::Renderer::onResume() {
Andreas Huberb58ce9f2011-11-28 16:27:35 -0800863 if (!mPaused) {
864 return;
865 }
Andreas Huberb4082222011-01-20 15:23:04 -0800866
867 if (mHasAudio) {
868 mAudioSink->start();
869 }
870
871 mPaused = false;
872
Wei Jiabc2fb722014-07-08 16:37:57 -0700873 Mutex::Autolock autoLock(mLock);
Andreas Huberb4082222011-01-20 15:23:04 -0800874 if (!mAudioQueue.empty()) {
Wei Jiabc2fb722014-07-08 16:37:57 -0700875 postDrainAudioQueue_l();
Andreas Huberb4082222011-01-20 15:23:04 -0800876 }
877
878 if (!mVideoQueue.empty()) {
879 postDrainVideoQueue();
880 }
881}
882
Andreas Huberf9334412010-12-15 15:17:42 -0800883} // namespace android
884