mmswadaptation/videorenderer/src/rendererrelay.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include <hal.h>
       
    22 #include <graphics/suerror.h>
       
    23 #include "rendererrelay.h"
       
    24 #include "buflistener.h"
       
    25 #include "buffermanager.h"
       
    26 #include "videoframebuffer.h"
       
    27 #include "rendererutil.h"
       
    28 #include "renderertimer.h"
       
    29 
       
    30 /** static factory contruction */
       
    31 CRendererRelay* CRendererRelay::NewL(MVideoRendererObserver& aObserver)
       
    32 	{
       
    33 	CRendererRelay* self = new (ELeave) CRendererRelay(aObserver);
       
    34 	CleanupStack::PushL(self);
       
    35 	self->ConstructL();
       
    36 	CleanupStack::Pop(self);
       
    37 	return self;
       
    38 	}
       
    39 
       
    40 CRendererRelay::CRendererRelay(MVideoRendererObserver& aObserver)
       
    41 :iObserver(aObserver), 
       
    42  iBufAvailListeners(CBufAvailListener::iOffset), 
       
    43  iAvailListenersIter(iBufAvailListeners)
       
    44 	{
       
    45 	}
       
    46 
       
    47 void CRendererRelay::ConstructL()
       
    48 	{
       
    49 	User::LeaveIfError(iSurfaceUpdateSession.Connect());
       
    50 	User::LeaveIfError(HAL::Get(HAL::EFastCounterFrequency, iFastCounterFrequency));
       
    51 	User::LeaveIfError(HAL::Get(HAL::EFastCounterCountsUp, iFastCounterCountsUp));
       
    52 	}
       
    53 
       
    54 /** Destructor */
       
    55 CRendererRelay::~CRendererRelay()
       
    56 	{
       
    57 	delete iDisplayListener;
       
    58 	
       
    59 	iAvailListenersIter.SetToFirst();
       
    60 	CBufAvailListener* listener = NULL;
       
    61 	while ((listener = iAvailListenersIter++) != NULL)
       
    62 		{
       
    63 		listener->iDblQueLink.Deque();
       
    64 		delete listener;
       
    65 		}
       
    66 	
       
    67 	iSurfaceUpdateSession.Close();
       
    68 	}
       
    69 
       
    70 /** Update buffer manager pointer in this class and listeners */
       
    71 void CRendererRelay::SetBufferManager(CRendererBufferManager* aBufManager)
       
    72 	{
       
    73 	iBufManager = aBufManager;
       
    74 	
       
    75 	// change buffer manager pointer for listeners
       
    76 	iAvailListenersIter.SetToFirst();
       
    77 	CBufAvailListener* listener = NULL;
       
    78 	while ((listener = iAvailListenersIter++) != NULL)
       
    79 		{
       
    80 		listener->SetBufferManager(aBufManager);
       
    81 		
       
    82 		if (!aBufManager && listener->IsAdded())
       
    83 			{
       
    84 			listener->Deque();
       
    85 			}
       
    86 		else if (aBufManager && !listener->IsAdded())
       
    87 			{
       
    88 			CActiveScheduler::Add(listener);
       
    89 			}
       
    90 		}
       
    91 	}
       
    92 
       
    93 /** Return the next unused CBufAvailListener. */
       
    94 CBufAvailListener* CRendererRelay::BufAvailListener()
       
    95 	{
       
    96 	CBufAvailListener* listener = NULL;
       
    97 	iAvailListenersIter.SetToFirst();
       
    98 	while ((listener = iAvailListenersIter++) != NULL)
       
    99 		{
       
   100 		if (listener->IsActive() == EFalse)
       
   101 			{
       
   102 			// Move to end so that the next search is a bit faster
       
   103 			listener->iDblQueLink.Deque();
       
   104 			iBufAvailListeners.AddLast(*listener);
       
   105 			return listener;
       
   106 			}
       
   107 		}
       
   108 
       
   109 	// Should not reach here as the number of listeners is same as number of buffer
       
   110 	__ASSERT_DEBUG(EFalse, User::Panic(_L("CRR::BufAvailListener"), KErrUnknown));
       
   111 	return listener;
       
   112 	}
       
   113 
       
   114 /** Set update parameter and create listeners */
       
   115 void CRendererRelay::PrepareL(const TSurfaceId& aSurfaceId, TInt aNumBuffers, TRequestStatus* /*aRequestStatus*/)
       
   116 	{
       
   117 	iUpdateSubmitted = EFalse;
       
   118 	iSurfaceId = aSurfaceId;
       
   119 	
       
   120 	if (!iDisplayListener)
       
   121 		{
       
   122 		iDisplayListener = CBufDisplayListener::NewL(iObserver, iSurfaceUpdateSession, *this, iFastCounterFrequency, iFastCounterCountsUp);
       
   123 		}
       
   124 
       
   125 	TInt numListeners = 0;
       
   126 	iAvailListenersIter.SetToFirst();
       
   127 	while (iAvailListenersIter++ != NULL)
       
   128 		{
       
   129 		numListeners++;
       
   130 		}
       
   131 	
       
   132 	CBufAvailListener* listener = NULL;
       
   133 	// create new listeners if there are more numBuffers than listeners
       
   134 	for (TInt i = numListeners; i < aNumBuffers; ++i)
       
   135 		{
       
   136 		listener = CBufAvailListener::NewL(iObserver, iSurfaceUpdateSession);
       
   137 		iBufAvailListeners.AddFirst(*listener);
       
   138 		}
       
   139 	}
       
   140 
       
   141 /** Handle update buffer request in non-timed mode */
       
   142 void CRendererRelay::UpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aPresentationTime, TRequestStatus* /* aRequestStatus */)
       
   143 	{
       
   144 	__ASSERT_DEBUG(iBufManager != NULL, User::Panic(_L("CRR::UpdateBuffer"), KErrNotReady));
       
   145 	
       
   146 	iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
       
   147 	
       
   148 	if (iUpdateSubmitted == EFalse)
       
   149 		{
       
   150 		// an update haven't been submitted, submit one now
       
   151 		SubmitBuffer();
       
   152 		}
       
   153 	}
       
   154 
       
   155 /** Callback from display listener that a buffer has been displayed or skipped*/
       
   156 void CRendererRelay::BufferDisplayed(TBool aDisplayed, TInt64 aDelay)
       
   157 	{
       
   158 	DEBUGPRINT3(_L("CRendererRelay::BufferDisplayed entered aDisplayed=%d, aDelay=%Ld"), aDisplayed, aDelay);
       
   159 
       
   160 	iUpdateSubmitted = EFalse;
       
   161 	
       
   162 	if (iRendererTimer)
       
   163 		{
       
   164 		// rendering in timed mode
       
   165 		if (aDisplayed)
       
   166 			{
       
   167 			// update delay value
       
   168 			iDelay = aDelay;
       
   169 			}
       
   170 		SubmitBufferTimed();
       
   171 		}
       
   172 	else
       
   173 		{
       
   174 		// rendering in non timed mode
       
   175 		SubmitBuffer();
       
   176 		}
       
   177 	}
       
   178 
       
   179 /** Submit the next buffer that is waiting to be submitted in non-timed mode*/
       
   180 void CRendererRelay::SubmitBuffer()
       
   181 	{
       
   182 	DEBUGPRINT1(_L("CRendererRelay::SubmitBuffer entered"));
       
   183 	__ASSERT_DEBUG(iBufManager != NULL, User::Panic(_L("CRR::SubmitBuffer"), KErrCorrupt));
       
   184 	__ASSERT_DEBUG(iUpdateSubmitted == EFalse, User::Panic(_L("CRR::SubmitBuffer"), KErrGeneral));
       
   185 
       
   186 	TBool lastBuf;
       
   187 	TVideoFrameBuffer* buf = iBufManager->WaitingBuffer(ETrue, lastBuf);
       
   188 	TInt numBufferSkipped = 0;
       
   189 	
       
   190 	TTime now;
       
   191 	now.UniversalTime();
       
   192 	TUint32 fastCounter = User::FastCounter();
       
   193 	while (buf != NULL)
       
   194 		{
       
   195 		TInt bufId = buf->BufferId();
       
   196 		
       
   197 		DEBUGPRINT4(_L("bufId=%d presTime=%Ld, now=%Ld"), 
       
   198 					bufId, buf->PresentationTime().Int64(), now.Int64());
       
   199 
       
   200 		// submit the buffer for update if presntation time is not in past 
       
   201 		// or if the buffer is the last in queue or presentation time is zero
       
   202 		if (buf->PresentationTime() >= now || lastBuf || buf->PresentationTime().Int64() == 0)
       
   203 			{
       
   204 			DoUpdateBuffer(bufId, now, fastCounter);
       
   205 			break;
       
   206 			}
       
   207 		
       
   208 		// The buffer presentation time occurs in past if codeflow reaches here.
       
   209 		// Change the buffer status to available and notify observer about the skipped buffer
       
   210 		iBufManager->BufferAvailable(bufId);
       
   211 		iObserver.MvroBufferSkipped(bufId);
       
   212 		numBufferSkipped++;
       
   213 
       
   214 		// get next buffer
       
   215 		buf = iBufManager->WaitingBuffer(ETrue, lastBuf);
       
   216 		}
       
   217 	
       
   218 	//notifiy observer about the available buffers
       
   219 	for (TInt i = 0; i < numBufferSkipped; ++i)
       
   220 		{
       
   221 		iObserver.MvroVideoBufferAvailable();
       
   222 		}
       
   223 	}
       
   224 
       
   225 /** Set a pointer to renderer timer in timed mode */
       
   226 void CRendererRelay::SetRendererTimer(CRendererTimer* aRendererTimer)
       
   227 	{
       
   228 	iRendererTimer = aRendererTimer;
       
   229 	}
       
   230 
       
   231 /** Callback function when a renderer timer has expired */
       
   232 void CRendererRelay::RendererTimerExpired()
       
   233 	{
       
   234 	SubmitBufferTimed();
       
   235 	}
       
   236 
       
   237 /** Submit the next buffer in timed mode */
       
   238 void CRendererRelay::SubmitBufferTimed()
       
   239 	{
       
   240 	DEBUGPRINT1(_L("CRendererRelay::SubmitBufferTimed entered"));
       
   241 
       
   242 	__ASSERT_DEBUG(iBufManager != NULL, User::Panic(_L("CRR::SubmitBufferTimed"), KErrCorrupt));
       
   243 	__ASSERT_DEBUG(iUpdateSubmitted == EFalse, 
       
   244 			User::Panic(_L("CRR::SubmitBufferTimed"), KErrGeneral));
       
   245 	__ASSERT_DEBUG(iRendererTimer && iRendererTimer->IsActive() == EFalse, 
       
   246 					User::Panic(_L("CRR::SubmitBufferTimed"), KErrInUse));
       
   247 	
       
   248 	TBool lastBuf;
       
   249 	TVideoFrameBuffer* buf = iBufManager->WaitingBuffer(EFalse, lastBuf);
       
   250 	TInt numBufferSkipped = 0;
       
   251 	
       
   252 	TTime now;
       
   253 	now.UniversalTime();
       
   254 	TUint32 fastCounter = User::FastCounter();
       
   255 	while (buf != NULL)
       
   256 		{
       
   257 		TInt bufId = buf->BufferId();
       
   258 		TTimeIntervalMicroSeconds deltaFromNow = buf->PresentationTime().MicroSecondsFrom(now);
       
   259 		
       
   260 		TInt64 waitTime = 0;
       
   261 		if (buf->PresentationTime().Int64() != 0)
       
   262 			{
       
   263 			// presentation time is not zero, calculate wait time. Otherwise, wait time is zero.
       
   264 			waitTime = deltaFromNow.Int64() - iDelay;
       
   265 			}
       
   266 		
       
   267 		DEBUGPRINT4(_L("bufId=%d presTime=%Ld, now=%Ld"), 
       
   268 				bufId, buf->PresentationTime().Int64(), now.Int64());
       
   269 
       
   270 		// submit the buffer for update if presntation time is not in past 
       
   271 		// or if the buffer is the last in queue
       
   272 		if (waitTime > 0)
       
   273 			{
       
   274 			iRendererTimer->Start(waitTime);
       
   275 			break;
       
   276 			}
       
   277 		else if (buf->PresentationTime().Int64() == 0 ||
       
   278 					deltaFromNow.Int64() + iMaxDelay >= 0 || 
       
   279 					lastBuf)
       
   280 			{
       
   281 			// if presentation time is zero (waitTime is not used for checking because it may be zero from calculation)
       
   282 			// or the frame is within maximun allowed delay, i.e. (presentation time + max delay >= now)
       
   283 			// or submission time has passed but this is the last buf, submit the buffer now
       
   284 
       
   285 			iBufManager->BufferSubmitted(buf);
       
   286 			DoUpdateBuffer(bufId, now, fastCounter);
       
   287 			break;
       
   288 			}
       
   289 		
       
   290 		// The buffer presentation time has passed maxDelay if codeflow reaches here, skip the buffer.
       
   291 		// Change the buffer status to available and notify observer
       
   292 		iBufManager->BufferAvailable(bufId);
       
   293 		iObserver.MvroBufferSkipped(bufId);
       
   294 		numBufferSkipped++;
       
   295 
       
   296 		// get next buffer
       
   297 		buf = iBufManager->WaitingBuffer(EFalse, lastBuf);
       
   298 		}
       
   299 	
       
   300 	//notifiy observer about the available buffers
       
   301 	for (TInt i = 0; i < numBufferSkipped; ++i)
       
   302 		{
       
   303 		iObserver.MvroVideoBufferAvailable();
       
   304 		}
       
   305 	}
       
   306 
       
   307 /**
       
   308 Submits a buffer to be updated at the specified time.
       
   309 */
       
   310 
       
   311 void CRendererRelay::DoUpdateBuffer(TInt aBufferId, const TTime& aTime, TUint32 aFastCounter)
       
   312 	{
       
   313 	CBufAvailListener* availListener = BufAvailListener();
       
   314 			
       
   315 	availListener->Start(aBufferId);
       
   316 	iDisplayListener->Start(aBufferId, aTime, aFastCounter);
       
   317 	
       
   318 	TInt err = iSurfaceUpdateSession.SubmitUpdate(KAllScreens, iSurfaceId, aBufferId);
       
   319 
       
   320 	DEBUGPRINT2(_L("SubmitUpdate return %d"), err);
       
   321 			
       
   322 	// error will also be returned from listener, so the next submit updated will be triggered by display listener
       
   323 	iUpdateSubmitted = ETrue;
       
   324 	}
       
   325 
       
   326 /** 
       
   327 Return ETrue if an update has been submitted and the display notification 
       
   328 haven't been received yet. i.e. Need to wait till for listener callback before 
       
   329 the next buffer can be submitted.
       
   330 */
       
   331 TBool CRendererRelay::UpdateSubmitted()
       
   332 	{
       
   333 	return iUpdateSubmitted;
       
   334 	}
       
   335 
       
   336 /** return the delay for surface update */
       
   337 TInt64 CRendererRelay::Delay()
       
   338 	{
       
   339 	return iDelay;
       
   340 	}
       
   341 
       
   342 /** Cancel all update notification when a surface is destroyed */
       
   343 void CRendererRelay::DestroySurface(TRequestStatus* /* aRequestStatus */ )
       
   344 	{
       
   345 	iSurfaceUpdateSession.CancelAllUpdateNotifications();
       
   346 	}
       
   347 
       
   348 /* This function is not used */
       
   349 void CRendererRelay::SetRendererThread(RThread* /* aRendererThread */)
       
   350 	{
       
   351 	__ASSERT_DEBUG(EFalse, User::Panic(_L("CRR::SetRendererThread"), KErrUnknown));
       
   352 	}
       
   353 
       
   354 /* This function is not used */
       
   355 void CRendererRelay::Terminate(TRequestStatus& /* aRequestStatus */)
       
   356 	{
       
   357 	__ASSERT_DEBUG(EFalse, User::Panic(_L("CRR::Terminate"), KErrUnknown));
       
   358 	}
       
   359 
       
   360 /** Set timer info for timed mode, this function is not called in non-timed mode */
       
   361 void CRendererRelay::SetTimerInfo(TInt64 aDefaultDelay, TInt64 aMaxDelay)
       
   362 	{
       
   363 	iDelay = aDefaultDelay;
       
   364 	iMaxDelay = aMaxDelay;
       
   365 	}
       
   366 
       
   367 /** Two-phased constructor. */
       
   368 CRendererThreadRelay* CRendererThreadRelay::NewL(MVideoRendererObserver& aObserver, TThreadId aMainThreadId)
       
   369 	{
       
   370 	CRendererThreadRelay* self = new (ELeave) CRendererThreadRelay(aObserver);
       
   371 	CleanupStack::PushL(self);
       
   372 	self->ConstructL(aMainThreadId);
       
   373 	CleanupStack::Pop(self);
       
   374 	return self;
       
   375 	}
       
   376 
       
   377 CRendererThreadRelay::CRendererThreadRelay(MVideoRendererObserver& aObserver) 
       
   378 : CActive(EPriorityStandard), iObserver(aObserver)
       
   379 	{
       
   380 	CActiveScheduler::Add(this);
       
   381 	}
       
   382 
       
   383 /** Second-phase constructor */
       
   384 void CRendererThreadRelay::ConstructL(TThreadId aMainThreadId)
       
   385 	{
       
   386 	User::LeaveIfError(iMainThread.Open(aMainThreadId));
       
   387 	iRendererRelay = CRendererRelay::NewL(*this);
       
   388 	iRendererTimer = CRendererTimer::NewL(*iRendererRelay);
       
   389 	iRendererRelay->SetRendererTimer(iRendererTimer);
       
   390 	}
       
   391 
       
   392 /** 
       
   393 Destructor. 
       
   394 This active object is always cancelled by main thread so no need to cancel this active object here
       
   395 */
       
   396 CRendererThreadRelay::~CRendererThreadRelay()
       
   397 	{
       
   398 	delete iRendererCallbackListener;
       
   399 	delete iRendererTimer;
       
   400 	delete iRendererRelay;
       
   401 	iMainThread.Close();
       
   402 	}
       
   403 
       
   404 void CRendererThreadRelay::DoCancel()
       
   405 	{
       
   406 	// Don't need to do anything, will be stopped by main thread
       
   407 	}
       
   408 
       
   409 /** Function for making the initial request */
       
   410 void CRendererThreadRelay::Start()
       
   411 	{
       
   412 	__ASSERT_DEBUG(IsActive() == EFalse, User::Panic(_L("CRTR::Start"), KErrInUse));
       
   413 	iStatus = KRequestPending;
       
   414 	SetActive();
       
   415 	}
       
   416 
       
   417 /** Handle requests from main thread */
       
   418 void CRendererThreadRelay::RunL()
       
   419 	{
       
   420 	__ASSERT_DEBUG(iStatus == KErrNone, User::Panic(_L("CRTR::RunL"), KErrUnknown));
       
   421 	TInt result = KErrNone;
       
   422 
       
   423 	if (iFunctionCode == ESubmitUpdate)
       
   424 		{
       
   425 		Start();
       
   426 		RunUpdateBuffer(iBuffer, iPresentationTime);
       
   427 		}
       
   428 	else if (iFunctionCode == EDestroySurface)
       
   429 		{
       
   430 		Start();
       
   431 		RunDestroySurface();
       
   432 		}
       
   433 	else if (iFunctionCode == EPrepare)
       
   434 		{
       
   435 		Start();
       
   436 		TRAP(result, RunPrepareL());
       
   437 		}
       
   438 	else if (iFunctionCode == ESetBufferManager)
       
   439 		{
       
   440 		Start();
       
   441 		RunSetBufferManager();
       
   442 		}
       
   443 	else // iFunctionCode == ETermination
       
   444 		{
       
   445 		CActiveScheduler::Stop();
       
   446 		}
       
   447 
       
   448 	TRequestStatus *status = iCallingStatus;
       
   449 	iMainThread.RequestComplete(status, result);
       
   450 	}
       
   451 
       
   452 /** Send a signal to the main thread to indicate that the thread startup was successful. */
       
   453 void CRendererThreadRelay::SignalSetupComplete(TRequestStatus* aSetupComplete)
       
   454 	{
       
   455 	iMainThread.RequestComplete(aSetupComplete, KErrNone);
       
   456 	}
       
   457 
       
   458 /** Send update buffer request from main thread to renderer thread */
       
   459 void CRendererThreadRelay::UpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aPresentationTime, TRequestStatus* aRequestStatus)
       
   460 	{
       
   461 	__ASSERT_DEBUG(aRequestStatus != NULL, User::Panic(_L("CRTR::UpdateBuffer"), KErrArgument));
       
   462 
       
   463 	// set function parameters
       
   464 	iCallingStatus = aRequestStatus;
       
   465 	iFunctionCode = ESubmitUpdate;
       
   466 	iBuffer = aBuffer;
       
   467 	iPresentationTime = aPresentationTime;
       
   468 	
       
   469 	// send request to renderer thread
       
   470 	TRequestStatus* rendererRequest = Status();
       
   471 	iRendererThread->RequestComplete(rendererRequest, KErrNone);
       
   472 	}
       
   473 
       
   474 /** Send terminate renderer thread request from main thread to renderer thread */
       
   475 void CRendererThreadRelay::Terminate(TRequestStatus& aRequestStatus)
       
   476 	{
       
   477 	iCallingStatus = &aRequestStatus;
       
   478 	iFunctionCode = ETermination;
       
   479 	
       
   480 	if (iRendererCallbackListener)
       
   481 		{
       
   482 		iRendererCallbackListener->Cancel();
       
   483 		}
       
   484 	
       
   485 	// send request to renderer thread
       
   486 	TRequestStatus* rendererRequest = Status();
       
   487 	iRendererThread->RequestComplete(rendererRequest, KErrNone);
       
   488 	}
       
   489 
       
   490 /** Send destroy surface request from main thread to renderer thread */
       
   491 void CRendererThreadRelay::DestroySurface(TRequestStatus* aRequestStatus)
       
   492 	{
       
   493 	__ASSERT_DEBUG(aRequestStatus != NULL, User::Panic(_L("CRTR::DestroySurface"), KErrArgument));
       
   494 	
       
   495 	iCallingStatus = aRequestStatus;
       
   496 	iFunctionCode = EDestroySurface;
       
   497 	
       
   498 	// send request to renderer thread
       
   499 	TRequestStatus* rendererRequest = Status();
       
   500 	iRendererThread->RequestComplete(rendererRequest, KErrNone);
       
   501 	}
       
   502 
       
   503 /* Prepare the object after a surface is created */
       
   504 void CRendererThreadRelay::PrepareL(const TSurfaceId& aSurfaceId, TInt aNumBuffers, TRequestStatus* aRequestStatus)
       
   505 	{
       
   506 	__ASSERT_DEBUG(aRequestStatus != NULL, User::Panic(_L("CRTR::PrepareL"), KErrArgument));
       
   507 	
       
   508 	if(!iRendererCallbackListener)
       
   509 		{
       
   510 		// first, create callback listener in the main thread
       
   511 		iRendererCallbackListener = CRendererCallbackListener::NewL(iObserver, aNumBuffers);
       
   512 		iRendererCallbackListener->Start();		
       
   513 		}
       
   514 	else if (iNumBuffers < aNumBuffers)
       
   515 		{
       
   516 		iRendererCallbackListener->Cancel();
       
   517 		iRendererCallbackListener->ExtendMsgQueueL(aNumBuffers);
       
   518 		iRendererCallbackListener->Start();		
       
   519 		}
       
   520 
       
   521 	// set function parameters
       
   522 	iCallingStatus = aRequestStatus;
       
   523 	iFunctionCode = EPrepare;
       
   524 	iSurfaceId = aSurfaceId;
       
   525 	iNumBuffers = aNumBuffers;
       
   526 	
       
   527 	// send request to renderer thread
       
   528 	TRequestStatus* rendererRequest = Status();
       
   529 	iRendererThread->RequestComplete(rendererRequest, KErrNone);
       
   530 	}
       
   531 
       
   532 /* Prepare the object after a surface is created */
       
   533 void CRendererThreadRelay::RunPrepareL()
       
   534 	{
       
   535 	iRendererRelay->PrepareL(iSurfaceId, iNumBuffers, NULL);
       
   536 	}
       
   537 
       
   538 /** Run update buffer in renderer thread */
       
   539 void CRendererThreadRelay::RunUpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aPresentationTime)
       
   540 	{
       
   541 	DEBUGPRINT1(_L("CRendererThreadRelay::RunUpdateBuffer entered"));
       
   542 	__ASSERT_DEBUG(iBufManager != NULL, User::Panic(_L("CRTR::RunUpdateBuffer"), KErrCorrupt));
       
   543 
       
   544 	/*
       
   545 	Buffer update is determined as follow:
       
   546 	 
       
   547 	If wait list is empty (imply no active timer), always add buffer to list, 
       
   548 		If a preceding buffer hasn't been displayed, the new buffer will be handled after display callback.
       
   549 			otherwise, decide whether timer should be started for submit update
       
   550 	If wait list is not empty (imply either timer is active or waiting for display callback)
       
   551 		If waiting for display callback, add new buffer to list and it will be handled after display callback.
       
   552 			(note: presentation time is not check because the new buffer may be newer than the waiting buffers even though both have passed due time)
       
   553 		If timer is active, first check if presentation time is zero. If so, display right away
       
   554 			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
       
   555 			otherwise, then check if presentation time < head list presentation time
       
   556 				if so, add the buffer to wait list, stop the timer and start timer with new time
       
   557 				else, just need to add buffer to wait list, the next timer expiry will hander the head buffer
       
   558 	*/
       
   559 	
       
   560 	if (iBufManager->WaitingListIsEmpty())
       
   561 		{
       
   562 		iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
       
   563 
       
   564 		if (iRendererRelay->UpdateSubmitted() == EFalse)
       
   565 			{
       
   566 			// an update haven't been submitted, prepare to submit one now
       
   567 			iRendererRelay->SubmitBufferTimed();
       
   568 			}
       
   569 		}
       
   570 	else
       
   571 		{
       
   572 		// waiting list is not empty
       
   573 		if (iRendererRelay->UpdateSubmitted())
       
   574 			{
       
   575 			// waiting for listener callback, just update waiting list
       
   576 			iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
       
   577 			}
       
   578 		else
       
   579 			{
       
   580 			// the timer is waiting
       
   581 
       
   582 			if (aPresentationTime.Int64() == 0)
       
   583 				{
       
   584 				// presentation time is zero, display right away.
       
   585 				iRendererTimer->Cancel();
       
   586 				iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
       
   587 				iRendererRelay->SubmitBufferTimed();
       
   588 				return;
       
   589 				}
       
   590 
       
   591 			TTime now;
       
   592 			now.UniversalTime();
       
   593 			TTimeIntervalMicroSeconds deltaFromNow = aPresentationTime.MicroSecondsFrom(now);
       
   594 			TInt64 waitTime = deltaFromNow.Int64() - iRendererRelay->Delay();
       
   595 				
       
   596 			if (waitTime <= 0)
       
   597 				{
       
   598 				// the wait time has passed
       
   599 				if (deltaFromNow.Int64() + iMaxDelay >= 0)
       
   600 					{
       
   601 					// the frame is within maximun allowed delay, i.e. (presentation time + max delay >= now)
       
   602 					// display right away
       
   603 					iRendererTimer->Cancel();
       
   604 					iBufManager->UpdateBuffer(aBuffer, aPresentationTime);
       
   605 					iRendererRelay->SubmitBufferTimed();
       
   606 					}
       
   607 				else
       
   608 					{
       
   609 					// skip the buffer
       
   610 					iBufManager->ReleaseBuffer(aBuffer);
       
   611 					MvroBufferSkipped(aBuffer->BufferId());
       
   612 	
       
   613 					//notifiy observer about the available buffers
       
   614 					MvroVideoBufferAvailable();
       
   615 					}
       
   616 				}
       
   617 			else
       
   618 				{
       
   619 				// wait time has not passed, add to waiting list
       
   620 				if (iBufManager->UpdateBuffer(aBuffer, aPresentationTime))
       
   621 					{
       
   622 					// head of waiting list has changed, start timer with new wait time
       
   623 					iRendererTimer->Cancel();
       
   624 					iRendererTimer->Start(waitTime);
       
   625 					}
       
   626 				}
       
   627 			}
       
   628 		}
       
   629 	}
       
   630 
       
   631 /** Run destroy surface in renderer thread */
       
   632 void CRendererThreadRelay::RunDestroySurface()
       
   633 	{
       
   634 	iRendererTimer->Cancel();
       
   635 	iRendererRelay->DestroySurface(NULL);
       
   636 	}
       
   637 
       
   638 /* Update buffer manager pointer */
       
   639 void CRendererThreadRelay::SetBufferManager(CRendererBufferManager* aBufManager)
       
   640 	{
       
   641 		TRequestStatus request = KRequestPending;
       
   642 		TRequestStatus logonRequest = KRequestPending;
       
   643 
       
   644 		// While a function call is in progress this thread is suspended
       
   645 		// and the undertaker will not catch panics, listen for these here
       
   646 		iRendererThread->Logon(logonRequest);
       
   647 
       
   648 		// Set the call parameters
       
   649 		iCallingStatus = &request;
       
   650 		iFunctionCode = ESetBufferManager;
       
   651 		iBufManager = aBufManager;
       
   652 	
       
   653 		// send request to renderer thread
       
   654 		TRequestStatus* rendererRequest = Status();
       
   655 		iRendererThread->RequestComplete(rendererRequest, KErrNone);
       
   656 		
       
   657 		User::WaitForRequest(logonRequest, request);
       
   658 
       
   659 		if(logonRequest != KRequestPending)
       
   660 			{
       
   661 			// renderer thread got panic from surface update session, so panic client
       
   662 			TInt reason = iRendererThread->ExitReason();
       
   663 			TExitCategoryName category = iRendererThread->ExitCategory();
       
   664 			User::Panic(category,reason);
       
   665 			}
       
   666 
       
   667 		// Thread is still alive and well
       
   668 		iRendererThread->LogonCancel(logonRequest);
       
   669 		User::WaitForRequest(logonRequest); // Consume the signal
       
   670 
       
   671 		__ASSERT_DEBUG(request != KRequestPending, User::Panic(_L("CRTR::SetBufferManager"), KErrCorrupt));
       
   672 	}
       
   673 
       
   674 void CRendererThreadRelay::RunSetBufferManager()
       
   675 	{
       
   676 	iRendererRelay->SetBufferManager(iBufManager);
       
   677 	}
       
   678 
       
   679 /** Store a pointer to the renderer thread object. */
       
   680 void CRendererThreadRelay::SetRendererThread(RThread* aRendererThread)
       
   681 	{
       
   682 	iRendererThread = aRendererThread;
       
   683 	}
       
   684 
       
   685 /** Return a pointer to the function call listener's request status. */
       
   686 TRequestStatus* CRendererThreadRelay::Status()
       
   687 	{
       
   688 	return &iStatus;
       
   689 	}
       
   690 
       
   691 /** Set timer info for timed mode */
       
   692 void CRendererThreadRelay::SetTimerInfo(TInt64 aDefaultDelay, TInt64 aMaxDelay)
       
   693 	{
       
   694 	iMaxDelay = aMaxDelay;
       
   695 	iRendererRelay->SetTimerInfo(aDefaultDelay, aMaxDelay);
       
   696 	}
       
   697 
       
   698 void CRendererThreadRelay::MvroVideoBufferAvailable()
       
   699 	{
       
   700 	iRendererCallbackListener->SendCallback(CRendererCallbackListener::EBufferAvailable, -1, 0);
       
   701 	}
       
   702 
       
   703 void CRendererThreadRelay::MvroBufferDisplayed(TInt aBufferId, const TTime& aTime)
       
   704 	{
       
   705 	iRendererCallbackListener->SendCallback(CRendererCallbackListener::EBufferDisplayed, aBufferId, aTime);
       
   706 	}
       
   707 
       
   708 void CRendererThreadRelay::MvroBufferSkipped(TInt aBufferId)
       
   709 	{
       
   710 	iRendererCallbackListener->SendCallback(CRendererCallbackListener::EBufferSkipped, aBufferId, 0);
       
   711 	}
       
   712 
       
   713 
       
   714 /** Private constructor */
       
   715 CRendererCallbackListener::CRendererCallbackListener(MVideoRendererObserver& aObserver)
       
   716 : CActive(EPriorityStandard),
       
   717   iObserver(aObserver)
       
   718 	{
       
   719 	CActiveScheduler::Add(this);
       
   720 	}
       
   721 
       
   722 /** Two-phased constructor */
       
   723 CRendererCallbackListener* CRendererCallbackListener::NewL(MVideoRendererObserver& aObserver, TInt aNumBuffer)
       
   724 	{
       
   725 	CRendererCallbackListener* self = new (ELeave) CRendererCallbackListener(aObserver);
       
   726 	CleanupStack::PushL(self);
       
   727 	self->ConstructL(aNumBuffer);
       
   728 	CleanupStack::Pop(self);
       
   729 	return self;
       
   730 	}
       
   731 
       
   732 /** Second-phase constructor */
       
   733 void CRendererCallbackListener::ConstructL(TInt aNumBuffer)
       
   734 	{
       
   735 	// There could potentially be three messages outstanding per buffer
       
   736 	// size message queue accordingly
       
   737 	TInt slot = aNumBuffer * 3;
       
   738 	if (slot > RMsgQueueBase::KMaxLength)
       
   739 		{
       
   740 		slot = RMsgQueueBase::KMaxLength;
       
   741 		}
       
   742 	User::LeaveIfError(iMsgQueue.CreateLocal(slot));
       
   743 	}
       
   744 
       
   745 CRendererCallbackListener::~CRendererCallbackListener()
       
   746 	{
       
   747 	Cancel(); // Cancel any request, if outstanding
       
   748 	iMsgQueue.Close();
       
   749 	}
       
   750 
       
   751 void CRendererCallbackListener::ExtendMsgQueueL(TInt aNumBuffer)
       
   752 	{
       
   753 	// close the message queue and construct another one
       
   754 	iMsgQueue.Close();
       
   755 	ConstructL(aNumBuffer);
       
   756 	}
       
   757 
       
   758 void CRendererCallbackListener::DoCancel()
       
   759 	{
       
   760 	iMsgQueue.CancelDataAvailable();
       
   761 	}
       
   762 
       
   763 /** Start listener */
       
   764 void CRendererCallbackListener::Start()
       
   765 	{
       
   766 	if (!IsActive())
       
   767 		{
       
   768 		iMsgQueue.NotifyDataAvailable(iStatus);
       
   769 		SetActive();
       
   770 		}
       
   771 	}
       
   772 
       
   773 /** Set the callback function */
       
   774 void CRendererCallbackListener::SendCallback(TFunctionCode aFunctionCode, TInt aBufferId, const TTime& aTime)
       
   775 	{
       
   776 	DEBUGPRINT2(_L("CRendererCallbackListener::SendCallback entered aFunctionCode=%d"), aFunctionCode);
       
   777 	
       
   778 	TCallbackData data;
       
   779 	data.iFunctionCode = aFunctionCode;
       
   780 	data.iBufferId = aBufferId;
       
   781 	data.iTime = aTime;
       
   782 	
       
   783 	iMsgQueue.Send(data);
       
   784 	}
       
   785 
       
   786 /** Call the callback function within the main thread */
       
   787 void CRendererCallbackListener::RunL()
       
   788 	{
       
   789 	TCallbackData data;
       
   790 	TInt err = iMsgQueue.Receive(data);
       
   791 	if (err == KErrNone)
       
   792 		{
       
   793 		if (data.iFunctionCode == EBufferAvailable)
       
   794 			{
       
   795 			DEBUGPRINT1(_L("CRendererCallbackListener::RunL - EBufferAvailable"));
       
   796 			iObserver.MvroVideoBufferAvailable();
       
   797 			}
       
   798 		else if (data.iFunctionCode == EBufferDisplayed)
       
   799 			{
       
   800 			DEBUGPRINT1(_L("CRendererCallbackListener::RunL - EBufferDisplayed"));
       
   801 			iObserver.MvroBufferDisplayed(data.iBufferId, data.iTime);
       
   802 			}
       
   803 		else if (data.iFunctionCode == EBufferSkipped)
       
   804 			{
       
   805 			DEBUGPRINT1(_L("CRendererCallbackListener::RunL - EBufferSkipped"));
       
   806 			iObserver.MvroBufferSkipped(data.iBufferId);
       
   807 			}
       
   808 		}
       
   809 	else
       
   810 		{
       
   811 		DEBUGPRINT2(_L("CRendererCallbackListener::RunL err=%d"), err);
       
   812 		}
       
   813 
       
   814 	Start();
       
   815 	}