1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/mmswadaptation/videorenderer/src/rendererrelay.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,815 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +/**
1.20 + @file
1.21 + @internalComponent
1.22 +*/
1.23 +
1.24 +#include <hal.h>
1.25 +#include <graphics/suerror.h>
1.26 +#include "rendererrelay.h"
1.27 +#include "buflistener.h"
1.28 +#include "buffermanager.h"
1.29 +#include "videoframebuffer.h"
1.30 +#include "rendererutil.h"
1.31 +#include "renderertimer.h"
1.32 +
1.33 +/** static factory contruction */
1.34 +CRendererRelay* CRendererRelay::NewL(MVideoRendererObserver& aObserver)
1.35 + {
1.36 + CRendererRelay* self = new (ELeave) CRendererRelay(aObserver);
1.37 + CleanupStack::PushL(self);
1.38 + self->ConstructL();
1.39 + CleanupStack::Pop(self);
1.40 + return self;
1.41 + }
1.42 +
1.43 +CRendererRelay::CRendererRelay(MVideoRendererObserver& aObserver)
1.44 +:iObserver(aObserver),
1.45 + iBufAvailListeners(CBufAvailListener::iOffset),
1.46 + iAvailListenersIter(iBufAvailListeners)
1.47 + {
1.48 + }
1.49 +
1.50 +void CRendererRelay::ConstructL()
1.51 + {
1.52 + User::LeaveIfError(iSurfaceUpdateSession.Connect());
1.53 + User::LeaveIfError(HAL::Get(HAL::EFastCounterFrequency, iFastCounterFrequency));
1.54 + User::LeaveIfError(HAL::Get(HAL::EFastCounterCountsUp, iFastCounterCountsUp));
1.55 + }
1.56 +
1.57 +/** Destructor */
1.58 +CRendererRelay::~CRendererRelay()
1.59 + {
1.60 + delete iDisplayListener;
1.61 +
1.62 + iAvailListenersIter.SetToFirst();
1.63 + CBufAvailListener* listener = NULL;
1.64 + while ((listener = iAvailListenersIter++) != NULL)
1.65 + {
1.66 + listener->iDblQueLink.Deque();
1.67 + delete listener;
1.68 + }
1.69 +
1.70 + iSurfaceUpdateSession.Close();
1.71 + }
1.72 +
1.73 +/** Update buffer manager pointer in this class and listeners */
1.74 +void CRendererRelay::SetBufferManager(CRendererBufferManager* aBufManager)
1.75 + {
1.76 + iBufManager = aBufManager;
1.77 +
1.78 + // change buffer manager pointer for listeners
1.79 + iAvailListenersIter.SetToFirst();
1.80 + CBufAvailListener* listener = NULL;
1.81 + while ((listener = iAvailListenersIter++) != NULL)
1.82 + {
1.83 + listener->SetBufferManager(aBufManager);
1.84 +
1.85 + if (!aBufManager && listener->IsAdded())
1.86 + {
1.87 + listener->Deque();
1.88 + }
1.89 + else if (aBufManager && !listener->IsAdded())
1.90 + {
1.91 + CActiveScheduler::Add(listener);
1.92 + }
1.93 + }
1.94 + }
1.95 +
1.96 +/** Return the next unused CBufAvailListener. */
1.97 +CBufAvailListener* CRendererRelay::BufAvailListener()
1.98 + {
1.99 + CBufAvailListener* listener = NULL;
1.100 + iAvailListenersIter.SetToFirst();
1.101 + while ((listener = iAvailListenersIter++) != NULL)
1.102 + {
1.103 + if (listener->IsActive() == EFalse)
1.104 + {
1.105 + // Move to end so that the next search is a bit faster
1.106 + listener->iDblQueLink.Deque();
1.107 + iBufAvailListeners.AddLast(*listener);
1.108 + return listener;
1.109 + }
1.110 + }
1.111 +
1.112 + // Should not reach here as the number of listeners is same as number of buffer
1.113 + __ASSERT_DEBUG(EFalse, User::Panic(_L("CRR::BufAvailListener"), KErrUnknown));
1.114 + return listener;
1.115 + }
1.116 +
1.117 +/** Set update parameter and create listeners */
1.118 +void CRendererRelay::PrepareL(const TSurfaceId& aSurfaceId, TInt aNumBuffers, TRequestStatus* /*aRequestStatus*/)
1.119 + {
1.120 + iUpdateSubmitted = EFalse;
1.121 + iSurfaceId = aSurfaceId;
1.122 +
1.123 + if (!iDisplayListener)
1.124 + {
1.125 + iDisplayListener = CBufDisplayListener::NewL(iObserver, iSurfaceUpdateSession, *this, iFastCounterFrequency, iFastCounterCountsUp);
1.126 + }
1.127 +
1.128 + TInt numListeners = 0;
1.129 + iAvailListenersIter.SetToFirst();
1.130 + while (iAvailListenersIter++ != NULL)
1.131 + {
1.132 + numListeners++;
1.133 + }
1.134 +
1.135 + CBufAvailListener* listener = NULL;
1.136 + // create new listeners if there are more numBuffers than listeners
1.137 + for (TInt i = numListeners; i < aNumBuffers; ++i)
1.138 + {
1.139 + listener = CBufAvailListener::NewL(iObserver, iSurfaceUpdateSession);
1.140 + iBufAvailListeners.AddFirst(*listener);
1.141 + }
1.142 + }
1.143 +
1.144 +/** Handle update buffer request in non-timed mode */
1.145 +void CRendererRelay::UpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aPresentationTime, TRequestStatus* /* aRequestStatus */)
1.146 + {
1.147 + __ASSERT_DEBUG(iBufManager != NULL, User::Panic(_L("CRR::UpdateBuffer"), KErrNotReady));
1.148 +
1.149 + iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
1.150 +
1.151 + if (iUpdateSubmitted == EFalse)
1.152 + {
1.153 + // an update haven't been submitted, submit one now
1.154 + SubmitBuffer();
1.155 + }
1.156 + }
1.157 +
1.158 +/** Callback from display listener that a buffer has been displayed or skipped*/
1.159 +void CRendererRelay::BufferDisplayed(TBool aDisplayed, TInt64 aDelay)
1.160 + {
1.161 + DEBUGPRINT3(_L("CRendererRelay::BufferDisplayed entered aDisplayed=%d, aDelay=%Ld"), aDisplayed, aDelay);
1.162 +
1.163 + iUpdateSubmitted = EFalse;
1.164 +
1.165 + if (iRendererTimer)
1.166 + {
1.167 + // rendering in timed mode
1.168 + if (aDisplayed)
1.169 + {
1.170 + // update delay value
1.171 + iDelay = aDelay;
1.172 + }
1.173 + SubmitBufferTimed();
1.174 + }
1.175 + else
1.176 + {
1.177 + // rendering in non timed mode
1.178 + SubmitBuffer();
1.179 + }
1.180 + }
1.181 +
1.182 +/** Submit the next buffer that is waiting to be submitted in non-timed mode*/
1.183 +void CRendererRelay::SubmitBuffer()
1.184 + {
1.185 + DEBUGPRINT1(_L("CRendererRelay::SubmitBuffer entered"));
1.186 + __ASSERT_DEBUG(iBufManager != NULL, User::Panic(_L("CRR::SubmitBuffer"), KErrCorrupt));
1.187 + __ASSERT_DEBUG(iUpdateSubmitted == EFalse, User::Panic(_L("CRR::SubmitBuffer"), KErrGeneral));
1.188 +
1.189 + TBool lastBuf;
1.190 + TVideoFrameBuffer* buf = iBufManager->WaitingBuffer(ETrue, lastBuf);
1.191 + TInt numBufferSkipped = 0;
1.192 +
1.193 + TTime now;
1.194 + now.UniversalTime();
1.195 + TUint32 fastCounter = User::FastCounter();
1.196 + while (buf != NULL)
1.197 + {
1.198 + TInt bufId = buf->BufferId();
1.199 +
1.200 + DEBUGPRINT4(_L("bufId=%d presTime=%Ld, now=%Ld"),
1.201 + bufId, buf->PresentationTime().Int64(), now.Int64());
1.202 +
1.203 + // submit the buffer for update if presntation time is not in past
1.204 + // or if the buffer is the last in queue or presentation time is zero
1.205 + if (buf->PresentationTime() >= now || lastBuf || buf->PresentationTime().Int64() == 0)
1.206 + {
1.207 + DoUpdateBuffer(bufId, now, fastCounter);
1.208 + break;
1.209 + }
1.210 +
1.211 + // The buffer presentation time occurs in past if codeflow reaches here.
1.212 + // Change the buffer status to available and notify observer about the skipped buffer
1.213 + iBufManager->BufferAvailable(bufId);
1.214 + iObserver.MvroBufferSkipped(bufId);
1.215 + numBufferSkipped++;
1.216 +
1.217 + // get next buffer
1.218 + buf = iBufManager->WaitingBuffer(ETrue, lastBuf);
1.219 + }
1.220 +
1.221 + //notifiy observer about the available buffers
1.222 + for (TInt i = 0; i < numBufferSkipped; ++i)
1.223 + {
1.224 + iObserver.MvroVideoBufferAvailable();
1.225 + }
1.226 + }
1.227 +
1.228 +/** Set a pointer to renderer timer in timed mode */
1.229 +void CRendererRelay::SetRendererTimer(CRendererTimer* aRendererTimer)
1.230 + {
1.231 + iRendererTimer = aRendererTimer;
1.232 + }
1.233 +
1.234 +/** Callback function when a renderer timer has expired */
1.235 +void CRendererRelay::RendererTimerExpired()
1.236 + {
1.237 + SubmitBufferTimed();
1.238 + }
1.239 +
1.240 +/** Submit the next buffer in timed mode */
1.241 +void CRendererRelay::SubmitBufferTimed()
1.242 + {
1.243 + DEBUGPRINT1(_L("CRendererRelay::SubmitBufferTimed entered"));
1.244 +
1.245 + __ASSERT_DEBUG(iBufManager != NULL, User::Panic(_L("CRR::SubmitBufferTimed"), KErrCorrupt));
1.246 + __ASSERT_DEBUG(iUpdateSubmitted == EFalse,
1.247 + User::Panic(_L("CRR::SubmitBufferTimed"), KErrGeneral));
1.248 + __ASSERT_DEBUG(iRendererTimer && iRendererTimer->IsActive() == EFalse,
1.249 + User::Panic(_L("CRR::SubmitBufferTimed"), KErrInUse));
1.250 +
1.251 + TBool lastBuf;
1.252 + TVideoFrameBuffer* buf = iBufManager->WaitingBuffer(EFalse, lastBuf);
1.253 + TInt numBufferSkipped = 0;
1.254 +
1.255 + TTime now;
1.256 + now.UniversalTime();
1.257 + TUint32 fastCounter = User::FastCounter();
1.258 + while (buf != NULL)
1.259 + {
1.260 + TInt bufId = buf->BufferId();
1.261 + TTimeIntervalMicroSeconds deltaFromNow = buf->PresentationTime().MicroSecondsFrom(now);
1.262 +
1.263 + TInt64 waitTime = 0;
1.264 + if (buf->PresentationTime().Int64() != 0)
1.265 + {
1.266 + // presentation time is not zero, calculate wait time. Otherwise, wait time is zero.
1.267 + waitTime = deltaFromNow.Int64() - iDelay;
1.268 + }
1.269 +
1.270 + DEBUGPRINT4(_L("bufId=%d presTime=%Ld, now=%Ld"),
1.271 + bufId, buf->PresentationTime().Int64(), now.Int64());
1.272 +
1.273 + // submit the buffer for update if presntation time is not in past
1.274 + // or if the buffer is the last in queue
1.275 + if (waitTime > 0)
1.276 + {
1.277 + iRendererTimer->Start(waitTime);
1.278 + break;
1.279 + }
1.280 + else if (buf->PresentationTime().Int64() == 0 ||
1.281 + deltaFromNow.Int64() + iMaxDelay >= 0 ||
1.282 + lastBuf)
1.283 + {
1.284 + // if presentation time is zero (waitTime is not used for checking because it may be zero from calculation)
1.285 + // or the frame is within maximun allowed delay, i.e. (presentation time + max delay >= now)
1.286 + // or submission time has passed but this is the last buf, submit the buffer now
1.287 +
1.288 + iBufManager->BufferSubmitted(buf);
1.289 + DoUpdateBuffer(bufId, now, fastCounter);
1.290 + break;
1.291 + }
1.292 +
1.293 + // The buffer presentation time has passed maxDelay if codeflow reaches here, skip the buffer.
1.294 + // Change the buffer status to available and notify observer
1.295 + iBufManager->BufferAvailable(bufId);
1.296 + iObserver.MvroBufferSkipped(bufId);
1.297 + numBufferSkipped++;
1.298 +
1.299 + // get next buffer
1.300 + buf = iBufManager->WaitingBuffer(EFalse, lastBuf);
1.301 + }
1.302 +
1.303 + //notifiy observer about the available buffers
1.304 + for (TInt i = 0; i < numBufferSkipped; ++i)
1.305 + {
1.306 + iObserver.MvroVideoBufferAvailable();
1.307 + }
1.308 + }
1.309 +
1.310 +/**
1.311 +Submits a buffer to be updated at the specified time.
1.312 +*/
1.313 +
1.314 +void CRendererRelay::DoUpdateBuffer(TInt aBufferId, const TTime& aTime, TUint32 aFastCounter)
1.315 + {
1.316 + CBufAvailListener* availListener = BufAvailListener();
1.317 +
1.318 + availListener->Start(aBufferId);
1.319 + iDisplayListener->Start(aBufferId, aTime, aFastCounter);
1.320 +
1.321 + TInt err = iSurfaceUpdateSession.SubmitUpdate(KAllScreens, iSurfaceId, aBufferId);
1.322 +
1.323 + DEBUGPRINT2(_L("SubmitUpdate return %d"), err);
1.324 +
1.325 + // error will also be returned from listener, so the next submit updated will be triggered by display listener
1.326 + iUpdateSubmitted = ETrue;
1.327 + }
1.328 +
1.329 +/**
1.330 +Return ETrue if an update has been submitted and the display notification
1.331 +haven't been received yet. i.e. Need to wait till for listener callback before
1.332 +the next buffer can be submitted.
1.333 +*/
1.334 +TBool CRendererRelay::UpdateSubmitted()
1.335 + {
1.336 + return iUpdateSubmitted;
1.337 + }
1.338 +
1.339 +/** return the delay for surface update */
1.340 +TInt64 CRendererRelay::Delay()
1.341 + {
1.342 + return iDelay;
1.343 + }
1.344 +
1.345 +/** Cancel all update notification when a surface is destroyed */
1.346 +void CRendererRelay::DestroySurface(TRequestStatus* /* aRequestStatus */ )
1.347 + {
1.348 + iSurfaceUpdateSession.CancelAllUpdateNotifications();
1.349 + }
1.350 +
1.351 +/* This function is not used */
1.352 +void CRendererRelay::SetRendererThread(RThread* /* aRendererThread */)
1.353 + {
1.354 + __ASSERT_DEBUG(EFalse, User::Panic(_L("CRR::SetRendererThread"), KErrUnknown));
1.355 + }
1.356 +
1.357 +/* This function is not used */
1.358 +void CRendererRelay::Terminate(TRequestStatus& /* aRequestStatus */)
1.359 + {
1.360 + __ASSERT_DEBUG(EFalse, User::Panic(_L("CRR::Terminate"), KErrUnknown));
1.361 + }
1.362 +
1.363 +/** Set timer info for timed mode, this function is not called in non-timed mode */
1.364 +void CRendererRelay::SetTimerInfo(TInt64 aDefaultDelay, TInt64 aMaxDelay)
1.365 + {
1.366 + iDelay = aDefaultDelay;
1.367 + iMaxDelay = aMaxDelay;
1.368 + }
1.369 +
1.370 +/** Two-phased constructor. */
1.371 +CRendererThreadRelay* CRendererThreadRelay::NewL(MVideoRendererObserver& aObserver, TThreadId aMainThreadId)
1.372 + {
1.373 + CRendererThreadRelay* self = new (ELeave) CRendererThreadRelay(aObserver);
1.374 + CleanupStack::PushL(self);
1.375 + self->ConstructL(aMainThreadId);
1.376 + CleanupStack::Pop(self);
1.377 + return self;
1.378 + }
1.379 +
1.380 +CRendererThreadRelay::CRendererThreadRelay(MVideoRendererObserver& aObserver)
1.381 +: CActive(EPriorityStandard), iObserver(aObserver)
1.382 + {
1.383 + CActiveScheduler::Add(this);
1.384 + }
1.385 +
1.386 +/** Second-phase constructor */
1.387 +void CRendererThreadRelay::ConstructL(TThreadId aMainThreadId)
1.388 + {
1.389 + User::LeaveIfError(iMainThread.Open(aMainThreadId));
1.390 + iRendererRelay = CRendererRelay::NewL(*this);
1.391 + iRendererTimer = CRendererTimer::NewL(*iRendererRelay);
1.392 + iRendererRelay->SetRendererTimer(iRendererTimer);
1.393 + }
1.394 +
1.395 +/**
1.396 +Destructor.
1.397 +This active object is always cancelled by main thread so no need to cancel this active object here
1.398 +*/
1.399 +CRendererThreadRelay::~CRendererThreadRelay()
1.400 + {
1.401 + delete iRendererCallbackListener;
1.402 + delete iRendererTimer;
1.403 + delete iRendererRelay;
1.404 + iMainThread.Close();
1.405 + }
1.406 +
1.407 +void CRendererThreadRelay::DoCancel()
1.408 + {
1.409 + // Don't need to do anything, will be stopped by main thread
1.410 + }
1.411 +
1.412 +/** Function for making the initial request */
1.413 +void CRendererThreadRelay::Start()
1.414 + {
1.415 + __ASSERT_DEBUG(IsActive() == EFalse, User::Panic(_L("CRTR::Start"), KErrInUse));
1.416 + iStatus = KRequestPending;
1.417 + SetActive();
1.418 + }
1.419 +
1.420 +/** Handle requests from main thread */
1.421 +void CRendererThreadRelay::RunL()
1.422 + {
1.423 + __ASSERT_DEBUG(iStatus == KErrNone, User::Panic(_L("CRTR::RunL"), KErrUnknown));
1.424 + TInt result = KErrNone;
1.425 +
1.426 + if (iFunctionCode == ESubmitUpdate)
1.427 + {
1.428 + Start();
1.429 + RunUpdateBuffer(iBuffer, iPresentationTime);
1.430 + }
1.431 + else if (iFunctionCode == EDestroySurface)
1.432 + {
1.433 + Start();
1.434 + RunDestroySurface();
1.435 + }
1.436 + else if (iFunctionCode == EPrepare)
1.437 + {
1.438 + Start();
1.439 + TRAP(result, RunPrepareL());
1.440 + }
1.441 + else if (iFunctionCode == ESetBufferManager)
1.442 + {
1.443 + Start();
1.444 + RunSetBufferManager();
1.445 + }
1.446 + else // iFunctionCode == ETermination
1.447 + {
1.448 + CActiveScheduler::Stop();
1.449 + }
1.450 +
1.451 + TRequestStatus *status = iCallingStatus;
1.452 + iMainThread.RequestComplete(status, result);
1.453 + }
1.454 +
1.455 +/** Send a signal to the main thread to indicate that the thread startup was successful. */
1.456 +void CRendererThreadRelay::SignalSetupComplete(TRequestStatus* aSetupComplete)
1.457 + {
1.458 + iMainThread.RequestComplete(aSetupComplete, KErrNone);
1.459 + }
1.460 +
1.461 +/** Send update buffer request from main thread to renderer thread */
1.462 +void CRendererThreadRelay::UpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aPresentationTime, TRequestStatus* aRequestStatus)
1.463 + {
1.464 + __ASSERT_DEBUG(aRequestStatus != NULL, User::Panic(_L("CRTR::UpdateBuffer"), KErrArgument));
1.465 +
1.466 + // set function parameters
1.467 + iCallingStatus = aRequestStatus;
1.468 + iFunctionCode = ESubmitUpdate;
1.469 + iBuffer = aBuffer;
1.470 + iPresentationTime = aPresentationTime;
1.471 +
1.472 + // send request to renderer thread
1.473 + TRequestStatus* rendererRequest = Status();
1.474 + iRendererThread->RequestComplete(rendererRequest, KErrNone);
1.475 + }
1.476 +
1.477 +/** Send terminate renderer thread request from main thread to renderer thread */
1.478 +void CRendererThreadRelay::Terminate(TRequestStatus& aRequestStatus)
1.479 + {
1.480 + iCallingStatus = &aRequestStatus;
1.481 + iFunctionCode = ETermination;
1.482 +
1.483 + if (iRendererCallbackListener)
1.484 + {
1.485 + iRendererCallbackListener->Cancel();
1.486 + }
1.487 +
1.488 + // send request to renderer thread
1.489 + TRequestStatus* rendererRequest = Status();
1.490 + iRendererThread->RequestComplete(rendererRequest, KErrNone);
1.491 + }
1.492 +
1.493 +/** Send destroy surface request from main thread to renderer thread */
1.494 +void CRendererThreadRelay::DestroySurface(TRequestStatus* aRequestStatus)
1.495 + {
1.496 + __ASSERT_DEBUG(aRequestStatus != NULL, User::Panic(_L("CRTR::DestroySurface"), KErrArgument));
1.497 +
1.498 + iCallingStatus = aRequestStatus;
1.499 + iFunctionCode = EDestroySurface;
1.500 +
1.501 + // send request to renderer thread
1.502 + TRequestStatus* rendererRequest = Status();
1.503 + iRendererThread->RequestComplete(rendererRequest, KErrNone);
1.504 + }
1.505 +
1.506 +/* Prepare the object after a surface is created */
1.507 +void CRendererThreadRelay::PrepareL(const TSurfaceId& aSurfaceId, TInt aNumBuffers, TRequestStatus* aRequestStatus)
1.508 + {
1.509 + __ASSERT_DEBUG(aRequestStatus != NULL, User::Panic(_L("CRTR::PrepareL"), KErrArgument));
1.510 +
1.511 + if(!iRendererCallbackListener)
1.512 + {
1.513 + // first, create callback listener in the main thread
1.514 + iRendererCallbackListener = CRendererCallbackListener::NewL(iObserver, aNumBuffers);
1.515 + iRendererCallbackListener->Start();
1.516 + }
1.517 + else if (iNumBuffers < aNumBuffers)
1.518 + {
1.519 + iRendererCallbackListener->Cancel();
1.520 + iRendererCallbackListener->ExtendMsgQueueL(aNumBuffers);
1.521 + iRendererCallbackListener->Start();
1.522 + }
1.523 +
1.524 + // set function parameters
1.525 + iCallingStatus = aRequestStatus;
1.526 + iFunctionCode = EPrepare;
1.527 + iSurfaceId = aSurfaceId;
1.528 + iNumBuffers = aNumBuffers;
1.529 +
1.530 + // send request to renderer thread
1.531 + TRequestStatus* rendererRequest = Status();
1.532 + iRendererThread->RequestComplete(rendererRequest, KErrNone);
1.533 + }
1.534 +
1.535 +/* Prepare the object after a surface is created */
1.536 +void CRendererThreadRelay::RunPrepareL()
1.537 + {
1.538 + iRendererRelay->PrepareL(iSurfaceId, iNumBuffers, NULL);
1.539 + }
1.540 +
1.541 +/** Run update buffer in renderer thread */
1.542 +void CRendererThreadRelay::RunUpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aPresentationTime)
1.543 + {
1.544 + DEBUGPRINT1(_L("CRendererThreadRelay::RunUpdateBuffer entered"));
1.545 + __ASSERT_DEBUG(iBufManager != NULL, User::Panic(_L("CRTR::RunUpdateBuffer"), KErrCorrupt));
1.546 +
1.547 + /*
1.548 + Buffer update is determined as follow:
1.549 +
1.550 + If wait list is empty (imply no active timer), always add buffer to list,
1.551 + If a preceding buffer hasn't been displayed, the new buffer will be handled after display callback.
1.552 + otherwise, decide whether timer should be started for submit update
1.553 + If wait list is not empty (imply either timer is active or waiting for display callback)
1.554 + If waiting for display callback, add new buffer to list and it will be handled after display callback.
1.555 + (note: presentation time is not check because the new buffer may be newer than the waiting buffers even though both have passed due time)
1.556 + If timer is active, first check if presentation time is zero. If so, display right away
1.557 + otherwise, then check if this frame can be timed (presentation time - delay <= now), if not, check max display to skip the frame or display right away
1.558 + otherwise, then check if presentation time < head list presentation time
1.559 + if so, add the buffer to wait list, stop the timer and start timer with new time
1.560 + else, just need to add buffer to wait list, the next timer expiry will hander the head buffer
1.561 + */
1.562 +
1.563 + if (iBufManager->WaitingListIsEmpty())
1.564 + {
1.565 + iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
1.566 +
1.567 + if (iRendererRelay->UpdateSubmitted() == EFalse)
1.568 + {
1.569 + // an update haven't been submitted, prepare to submit one now
1.570 + iRendererRelay->SubmitBufferTimed();
1.571 + }
1.572 + }
1.573 + else
1.574 + {
1.575 + // waiting list is not empty
1.576 + if (iRendererRelay->UpdateSubmitted())
1.577 + {
1.578 + // waiting for listener callback, just update waiting list
1.579 + iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
1.580 + }
1.581 + else
1.582 + {
1.583 + // the timer is waiting
1.584 +
1.585 + if (aPresentationTime.Int64() == 0)
1.586 + {
1.587 + // presentation time is zero, display right away.
1.588 + iRendererTimer->Cancel();
1.589 + iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
1.590 + iRendererRelay->SubmitBufferTimed();
1.591 + return;
1.592 + }
1.593 +
1.594 + TTime now;
1.595 + now.UniversalTime();
1.596 + TTimeIntervalMicroSeconds deltaFromNow = aPresentationTime.MicroSecondsFrom(now);
1.597 + TInt64 waitTime = deltaFromNow.Int64() - iRendererRelay->Delay();
1.598 +
1.599 + if (waitTime <= 0)
1.600 + {
1.601 + // the wait time has passed
1.602 + if (deltaFromNow.Int64() + iMaxDelay >= 0)
1.603 + {
1.604 + // the frame is within maximun allowed delay, i.e. (presentation time + max delay >= now)
1.605 + // display right away
1.606 + iRendererTimer->Cancel();
1.607 + iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
1.608 + iRendererRelay->SubmitBufferTimed();
1.609 + }
1.610 + else
1.611 + {
1.612 + // skip the buffer
1.613 + iBufManager->ReleaseBuffer(aBuffer);
1.614 + MvroBufferSkipped(aBuffer->BufferId());
1.615 +
1.616 + //notifiy observer about the available buffers
1.617 + MvroVideoBufferAvailable();
1.618 + }
1.619 + }
1.620 + else
1.621 + {
1.622 + // wait time has not passed, add to waiting list
1.623 + if (iBufManager->UpdateBuffer(aBuffer, aPresentationTime))
1.624 + {
1.625 + // head of waiting list has changed, start timer with new wait time
1.626 + iRendererTimer->Cancel();
1.627 + iRendererTimer->Start(waitTime);
1.628 + }
1.629 + }
1.630 + }
1.631 + }
1.632 + }
1.633 +
1.634 +/** Run destroy surface in renderer thread */
1.635 +void CRendererThreadRelay::RunDestroySurface()
1.636 + {
1.637 + iRendererTimer->Cancel();
1.638 + iRendererRelay->DestroySurface(NULL);
1.639 + }
1.640 +
1.641 +/* Update buffer manager pointer */
1.642 +void CRendererThreadRelay::SetBufferManager(CRendererBufferManager* aBufManager)
1.643 + {
1.644 + TRequestStatus request = KRequestPending;
1.645 + TRequestStatus logonRequest = KRequestPending;
1.646 +
1.647 + // While a function call is in progress this thread is suspended
1.648 + // and the undertaker will not catch panics, listen for these here
1.649 + iRendererThread->Logon(logonRequest);
1.650 +
1.651 + // Set the call parameters
1.652 + iCallingStatus = &request;
1.653 + iFunctionCode = ESetBufferManager;
1.654 + iBufManager = aBufManager;
1.655 +
1.656 + // send request to renderer thread
1.657 + TRequestStatus* rendererRequest = Status();
1.658 + iRendererThread->RequestComplete(rendererRequest, KErrNone);
1.659 +
1.660 + User::WaitForRequest(logonRequest, request);
1.661 +
1.662 + if(logonRequest != KRequestPending)
1.663 + {
1.664 + // renderer thread got panic from surface update session, so panic client
1.665 + TInt reason = iRendererThread->ExitReason();
1.666 + TExitCategoryName category = iRendererThread->ExitCategory();
1.667 + User::Panic(category,reason);
1.668 + }
1.669 +
1.670 + // Thread is still alive and well
1.671 + iRendererThread->LogonCancel(logonRequest);
1.672 + User::WaitForRequest(logonRequest); // Consume the signal
1.673 +
1.674 + __ASSERT_DEBUG(request != KRequestPending, User::Panic(_L("CRTR::SetBufferManager"), KErrCorrupt));
1.675 + }
1.676 +
1.677 +void CRendererThreadRelay::RunSetBufferManager()
1.678 + {
1.679 + iRendererRelay->SetBufferManager(iBufManager);
1.680 + }
1.681 +
1.682 +/** Store a pointer to the renderer thread object. */
1.683 +void CRendererThreadRelay::SetRendererThread(RThread* aRendererThread)
1.684 + {
1.685 + iRendererThread = aRendererThread;
1.686 + }
1.687 +
1.688 +/** Return a pointer to the function call listener's request status. */
1.689 +TRequestStatus* CRendererThreadRelay::Status()
1.690 + {
1.691 + return &iStatus;
1.692 + }
1.693 +
1.694 +/** Set timer info for timed mode */
1.695 +void CRendererThreadRelay::SetTimerInfo(TInt64 aDefaultDelay, TInt64 aMaxDelay)
1.696 + {
1.697 + iMaxDelay = aMaxDelay;
1.698 + iRendererRelay->SetTimerInfo(aDefaultDelay, aMaxDelay);
1.699 + }
1.700 +
1.701 +void CRendererThreadRelay::MvroVideoBufferAvailable()
1.702 + {
1.703 + iRendererCallbackListener->SendCallback(CRendererCallbackListener::EBufferAvailable, -1, 0);
1.704 + }
1.705 +
1.706 +void CRendererThreadRelay::MvroBufferDisplayed(TInt aBufferId, const TTime& aTime)
1.707 + {
1.708 + iRendererCallbackListener->SendCallback(CRendererCallbackListener::EBufferDisplayed, aBufferId, aTime);
1.709 + }
1.710 +
1.711 +void CRendererThreadRelay::MvroBufferSkipped(TInt aBufferId)
1.712 + {
1.713 + iRendererCallbackListener->SendCallback(CRendererCallbackListener::EBufferSkipped, aBufferId, 0);
1.714 + }
1.715 +
1.716 +
1.717 +/** Private constructor */
1.718 +CRendererCallbackListener::CRendererCallbackListener(MVideoRendererObserver& aObserver)
1.719 +: CActive(EPriorityStandard),
1.720 + iObserver(aObserver)
1.721 + {
1.722 + CActiveScheduler::Add(this);
1.723 + }
1.724 +
1.725 +/** Two-phased constructor */
1.726 +CRendererCallbackListener* CRendererCallbackListener::NewL(MVideoRendererObserver& aObserver, TInt aNumBuffer)
1.727 + {
1.728 + CRendererCallbackListener* self = new (ELeave) CRendererCallbackListener(aObserver);
1.729 + CleanupStack::PushL(self);
1.730 + self->ConstructL(aNumBuffer);
1.731 + CleanupStack::Pop(self);
1.732 + return self;
1.733 + }
1.734 +
1.735 +/** Second-phase constructor */
1.736 +void CRendererCallbackListener::ConstructL(TInt aNumBuffer)
1.737 + {
1.738 + // There could potentially be three messages outstanding per buffer
1.739 + // size message queue accordingly
1.740 + TInt slot = aNumBuffer * 3;
1.741 + if (slot > RMsgQueueBase::KMaxLength)
1.742 + {
1.743 + slot = RMsgQueueBase::KMaxLength;
1.744 + }
1.745 + User::LeaveIfError(iMsgQueue.CreateLocal(slot));
1.746 + }
1.747 +
1.748 +CRendererCallbackListener::~CRendererCallbackListener()
1.749 + {
1.750 + Cancel(); // Cancel any request, if outstanding
1.751 + iMsgQueue.Close();
1.752 + }
1.753 +
1.754 +void CRendererCallbackListener::ExtendMsgQueueL(TInt aNumBuffer)
1.755 + {
1.756 + // close the message queue and construct another one
1.757 + iMsgQueue.Close();
1.758 + ConstructL(aNumBuffer);
1.759 + }
1.760 +
1.761 +void CRendererCallbackListener::DoCancel()
1.762 + {
1.763 + iMsgQueue.CancelDataAvailable();
1.764 + }
1.765 +
1.766 +/** Start listener */
1.767 +void CRendererCallbackListener::Start()
1.768 + {
1.769 + if (!IsActive())
1.770 + {
1.771 + iMsgQueue.NotifyDataAvailable(iStatus);
1.772 + SetActive();
1.773 + }
1.774 + }
1.775 +
1.776 +/** Set the callback function */
1.777 +void CRendererCallbackListener::SendCallback(TFunctionCode aFunctionCode, TInt aBufferId, const TTime& aTime)
1.778 + {
1.779 + DEBUGPRINT2(_L("CRendererCallbackListener::SendCallback entered aFunctionCode=%d"), aFunctionCode);
1.780 +
1.781 + TCallbackData data;
1.782 + data.iFunctionCode = aFunctionCode;
1.783 + data.iBufferId = aBufferId;
1.784 + data.iTime = aTime;
1.785 +
1.786 + iMsgQueue.Send(data);
1.787 + }
1.788 +
1.789 +/** Call the callback function within the main thread */
1.790 +void CRendererCallbackListener::RunL()
1.791 + {
1.792 + TCallbackData data;
1.793 + TInt err = iMsgQueue.Receive(data);
1.794 + if (err == KErrNone)
1.795 + {
1.796 + if (data.iFunctionCode == EBufferAvailable)
1.797 + {
1.798 + DEBUGPRINT1(_L("CRendererCallbackListener::RunL - EBufferAvailable"));
1.799 + iObserver.MvroVideoBufferAvailable();
1.800 + }
1.801 + else if (data.iFunctionCode == EBufferDisplayed)
1.802 + {
1.803 + DEBUGPRINT1(_L("CRendererCallbackListener::RunL - EBufferDisplayed"));
1.804 + iObserver.MvroBufferDisplayed(data.iBufferId, data.iTime);
1.805 + }
1.806 + else if (data.iFunctionCode == EBufferSkipped)
1.807 + {
1.808 + DEBUGPRINT1(_L("CRendererCallbackListener::RunL - EBufferSkipped"));
1.809 + iObserver.MvroBufferSkipped(data.iBufferId);
1.810 + }
1.811 + }
1.812 + else
1.813 + {
1.814 + DEBUGPRINT2(_L("CRendererCallbackListener::RunL err=%d"), err);
1.815 + }
1.816 +
1.817 + Start();
1.818 + }