omxilvideocomps/omxilclock/src/clocksupervisor.h
changeset 0 5d29cba61097
equal deleted inserted replaced
-1:000000000000 0:5d29cba61097
       
     1 /*
       
     2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #ifndef CLOCKSUPERVISOR_H_
       
    20 #define CLOCKSUPERVISOR_H_
       
    21 
       
    22 #include <e32base.h>
       
    23 #include <openmax/il/khronos/v1_x/OMX_Other.h>
       
    24 
       
    25 /**
       
    26  @file
       
    27  @internalComponent
       
    28  */
       
    29 
       
    30 // forward declaration as supervisor calls back to processing function
       
    31 class COmxILClockProcessingFunction;
       
    32 
       
    33 ///////////////////////////////////////////////////////////////////////////////
       
    34 // List of structures declared in this file:
       
    35 // 
       
    36 // TMediaRequest
       
    37 // TEntryPoint
       
    38 // TIndexToFunctionMapping
       
    39 // CClockSupervisor
       
    40 // 
       
    41 ///////////////////////////////////////////////////////////////////////////////
       
    42 // Storage of Clock requests.
       
    43 //
       
    44 // The Media Update storage holds a number of request updates to send to 
       
    45 // clients.
       
    46 // The updates are entered in a queue based on the delta of the 
       
    47 // 'expected MediaTime minus Offset' giving an absolute time (the delta). 
       
    48 // This difference is then calculated by the queue implementation on insertion
       
    49 // of the element.
       
    50 //
       
    51 // When the clock changes state it notifies the clients by sending them a state 
       
    52 // change notification broadcast.
       
    53 // The important thing to note here is that there is no seperate queue for 
       
    54 // outgoing notifications.
       
    55 // As soon as a request timer expires that request is forwarded. 
       
    56 // Broadcast requests are raised and placed first on the queue so are sent 
       
    57 // as and when they occur.
       
    58 //
       
    59 // When the scale is a change of direction (i.e. playing in the backwards 
       
    60 // direction), the queue is cleared and the delta's absolute value is taken.
       
    61 // 
       
    62 // The delta is a TInt which matches the Ticks datatype returned by the system.
       
    63 // 
       
    64 // We do not expect the phone to be in operation beyond the maximum duration 
       
    65 // held by the 64-bit Wall clock. Behaviour beyond this is undefined.
       
    66 //
       
    67 // The reason for choosing a list over an array is mainly access efficiency.
       
    68 //
       
    69 // 1) The insertions must be in order so as to be pulled off quickly.
       
    70 //    Updates are pulled off from the front of the queue, so you would have 
       
    71 //    to adjust the whole array each time.
       
    72 // 2) Updates arrive at different times and can expect to be fulfilled prior 
       
    73 //    to earlier updates, again the list would need to be adjusted after the 
       
    74 //    point of insertion.
       
    75 // 
       
    76 // Clients are attached via ports and the notifications are sent to them via 
       
    77 // these ports
       
    78 //
       
    79 ///////////////////////////////////////////////////////////////////////////////
       
    80 // Clock functionality is invoked both externally & internally.
       
    81 //
       
    82 // Based on the OMX IL 1.1.1 standard, we route these incoming external 
       
    83 // requests to their relevant behaviour.
       
    84 //
       
    85 // This Clock component is intended to be created per use case.
       
    86 // That is for every use case that requires synchronisation.
       
    87 // This could result in several clocks being created, each with an audio and/or
       
    88 // video as an input, and each with a high-priority clock thread.
       
    89 // At most it is considered that there should only be a few of these components
       
    90 // in existance at any one time, as mobile devices should not really require it.
       
    91 // However, saying this, it should be factored into the design. 
       
    92 // At this stage it is envisioned that any clock component should reduce its 
       
    93 // timer events to once at just after the 32-bit wraparound when its 
       
    94 // application is not in focus. 
       
    95 // This is due to the time being reported to us in a 32-bit value, whilst our 
       
    96 // Wall clock is 64-bits. 
       
    97 // To avoid any wraparound and losing time by not regulary updating the upper 
       
    98 // word of our wall clock, we need to somehow check the system clock at this 
       
    99 // inteval. This is not a problem during normal operation but can be when the 
       
   100 // application is Paused or goes out of focus.
       
   101 //
       
   102 // NOTE: Assumes OMX_SKIP64BIT is not set when building OMX CORE
       
   103 ///////////////////////////////////////////////////////////////////////////////
       
   104 
       
   105 
       
   106 /**
       
   107  * 
       
   108  *
       
   109  */
       
   110 class TMediaRequest
       
   111 	{
       
   112 public:
       
   113 	TInt64 iMediaTime;
       
   114 	TInt64 iOffset;
       
   115 	TInt64 iTriggerWallTime;		// == iWallTimeAtMediaTime - iOffset
       
   116 	TInt iPortIndex;
       
   117 	TAny* iClientPrivate;
       
   118 	
       
   119 	inline void Deque();
       
   120 	inline void AddBefore(TMediaRequest*);
       
   121 	
       
   122 public:
       
   123 	TMediaRequest *iPrev;
       
   124 	TMediaRequest *iNext;
       
   125 	};
       
   126 
       
   127 /**
       
   128  * 
       
   129  *
       
   130  */
       
   131 class TMediaTimeContext
       
   132 	{
       
   133 public:
       
   134 	TMediaTimeContext(): iScaleQ16 (1 << 16), iInverseScaleQ16 (1 << 16)
       
   135 		{/*do nothing*/};
       
   136 
       
   137 	void SetScaleQ16(TInt32 aScaleQ16, TInt64 aWallTimeNow);
       
   138 public:
       
   139 	TInt64 iWallTimeBase;
       
   140 	TInt64 iMediaTimeBase;
       
   141 	
       
   142 	/**
       
   143 	 * Scale ranges map to modes of playback.
       
   144 	 * A Q16 value relative to a 1X forward advancement of the media clock.
       
   145 	 */
       
   146 	TInt32 iScaleQ16;
       
   147 	
       
   148 	/**
       
   149 	 * The reciprocal of iScaleQ16 (i.e. 1 / iScaleQ16), but adjusted for the
       
   150 	 * Q16 format.
       
   151 	 * 
       
   152 	 * It therefore has the value 2^32 / iScaleQ16.
       
   153 	 * 
       
   154 	 * If iScaleQ16 == 0, this field takes the value KMaxTInt (2^31 - 1)
       
   155 	 * 
       
   156 	 * If magnitude of iInverseScaleQ16 would be too large for a signed 32-bit
       
   157 	 * value, the value is clipped to KMaxTInt or KMinTInt (-2^31 or
       
   158 	 * (2^31 - 1)). This can only happen if iScaleQ16 == +/- 1.
       
   159 	 */
       
   160 	TInt32 iInverseScaleQ16;
       
   161 	};
       
   162 
       
   163 /**
       
   164  * 
       
   165  *
       
   166  */
       
   167 class TRequestDeltaQue
       
   168 	{
       
   169 public:
       
   170 	TRequestDeltaQue();
       
   171 	
       
   172 	void Add(TMediaRequest* aElement, TInt64 aDelta);
       
   173 	TMediaRequest* RemoveFirst();
       
   174 	TBool FirstDelta(TInt64& aDelta) const;
       
   175 	void RecalculateAndReorder(TMediaTimeContext& aMTC);
       
   176 	TBool IsEmpty() const;
       
   177 	TUint Count() const;
       
   178 	
       
   179 private:
       
   180 	TBool InsertBeforeFoundPosition(TInt64 aDelta, TMediaRequest*& aItem) const;
       
   181 
       
   182 #ifdef _DEBUG
       
   183 	void DbgCheck() const;
       
   184 #endif
       
   185 #ifdef _OMXIL_COMMON_DEBUG_TRACING_ON
       
   186 	void DbgPrint() const;
       
   187 #endif
       
   188 
       
   189 private:
       
   190 	TMediaRequest* iHead;
       
   191 	TInt iCount;
       
   192 	};
       
   193 
       
   194 
       
   195 /**
       
   196  * 
       
   197  *
       
   198  */
       
   199 class CClockSupervisor : public CBase
       
   200 	{
       
   201 public:
       
   202 #ifdef STABILITY_TEST_WRAPPER
       
   203 	friend class CStabilityTestWrapper;
       
   204 	friend class CStabilityTestNegativeWrapper;
       
   205 #endif
       
   206 friend class CClockThreadNotifier;	
       
   207 public:
       
   208 	static CClockSupervisor* NewL(COmxILClockProcessingFunction& aCallbacks);
       
   209 	~CClockSupervisor();
       
   210 
       
   211 	/**
       
   212 	 * Defines how a request arrived at the clock component
       
   213 	 */
       
   214 	enum TEntryPoint
       
   215 		{
       
   216 		EGetConfig,
       
   217 		ESetConfig
       
   218 		};
       
   219 	
       
   220 	// Producer function
       
   221 	// Invoked via clients of this component, i.e. GetConfig() and SetConfig()
       
   222 	OMX_ERRORTYPE ProduceRequest(OMX_INDEXTYPE aIndex, TEntryPoint aEntryPoint,
       
   223 								 TAny* aPassedStructPtr);
       
   224 								 
       
   225 	const OMX_TIME_CONFIG_CLOCKSTATETYPE GetMediaClockState() const
       
   226 		{
       
   227 		return iMediaClockState;
       
   228 		}
       
   229 
       
   230 private:
       
   231 	CClockSupervisor(COmxILClockProcessingFunction& aProcessingFunction);
       
   232 	void ConstructL();
       
   233 
       
   234 private:
       
   235 	//////////////
       
   236 	// This section describes the Clock thread related functions
       
   237 	//////////////
       
   238 	
       
   239 	// The timing thread's entry point
       
   240 	static TInt ThreadEntryPoint(TAny* aPtr);
       
   241 	void RunTimingThreadL();
       
   242 	
       
   243 private:
       
   244 	//////////////
       
   245 	// This section describes the request handler functions
       
   246 	//////////////
       
   247 
       
   248 	// From the Audio/Video feeds
       
   249 	OMX_ERRORTYPE HandleUpdateAudioReference(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   250 	OMX_ERRORTYPE HandleUpdateVideoReference(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   251 	
       
   252 	// From the OMX component
       
   253 	OMX_ERRORTYPE HandleSetPortClientStartTime(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   254 	OMX_ERRORTYPE HandleSubmitMediaTimeRequest(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   255 
       
   256 	// From the IL client
       
   257 	OMX_ERRORTYPE HandleGetSetTimeScale(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   258 	OMX_ERRORTYPE HandleGetSetSeekMode(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   259 	OMX_ERRORTYPE HandleGetSetClockState(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   260 	OMX_ERRORTYPE HandleGetSetActiveRefClock(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   261 
       
   262 	// Called from either IL client or IL components
       
   263 	OMX_ERRORTYPE HandleQueryCurrentWallTime(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   264 	OMX_ERRORTYPE HandleQueryCurrentMediaTime(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
       
   265 	
       
   266 private:
       
   267 	//////////////
       
   268 	// This section describes the Clock components internal house-keeping 
       
   269 	// routines
       
   270 	//////////////
       
   271 
       
   272 	// Perform actions related to placing the clock into the Stopped state
       
   273 	void DoTransitionToStoppedState();
       
   274 	
       
   275 	// Perform actions related to placing the clock into the Running state
       
   276 	void DoTransitionToRunningState();
       
   277 	
       
   278 	// Perform actions related to placing the clock into the Waiting state
       
   279 	void DoTransitionToWaitingState(OMX_U32 nWaitMask);
       
   280 	
       
   281 	// Update the tick counter, generating higher 32 bits
       
   282 	void UpdateWallTicks();
       
   283 	
       
   284 	// Consumer function
       
   285 	// Invoked at initialisation and runs in event loop.
       
   286 	TInt ConsumeRequests();
       
   287 	
       
   288 	// The timer loop to enable us to wake up on heart beat or requests
       
   289 	void TimerLoop();
       
   290 
       
   291 	// obtains the most appropriate start time based on scale (direction)
       
   292 	void CalculateStartTime();
       
   293 	
       
   294 	// reports whether all clients have reported their start times
       
   295 	TBool AllStartTimesReported();
       
   296 	
       
   297 	TInt64 WallTime();
       
   298 	
       
   299 	void UpdateMediaTime(TInt64 aMediaTime);
       
   300 	void BroadcastUpdate(const OMX_TIME_MEDIATIMETYPE& aUpdate);
       
   301 	
       
   302 	// reports error when clock thread panics
       
   303 	
       
   304 	void ReportClockThreadPanic();
       
   305 	
       
   306 private:
       
   307 	//////////////
       
   308 	// This section describes the clock's miscellaneous structures
       
   309 	//////////////
       
   310 
       
   311 	/**
       
   312 	 * State of the clock component's media clock:
       
   313 	 */
       
   314 	OMX_TIME_CONFIG_CLOCKSTATETYPE iMediaClockState;
       
   315 
       
   316 	/**
       
   317 	 * Choice of the clock component's reference clock:
       
   318 	 */
       
   319 	OMX_TIME_REFCLOCKTYPE iActiveRefClock;
       
   320 	
       
   321 	/**
       
   322 	 * Array of clients' start times:
       
   323 	 */
       
   324 	RArray<TInt64> iStartTimes;
       
   325 	TUint iStartTimesSet;			/* bit mask representing which elements of
       
   326 	                                   the start time array are valid */
       
   327 
       
   328 private:
       
   329 	//////////////
       
   330 	// This section describes the Clock component's routing structures
       
   331 	//////////////
       
   332 	
       
   333 	/*
       
   334 	 * typedef for function to handle incoming requests
       
   335 	 */
       
   336 	typedef OMX_ERRORTYPE (CClockSupervisor::*FunctionPtr)(TEntryPoint, OMX_PTR);
       
   337 
       
   338 	/*
       
   339 	 * Function jump table. Note that this is declared in class scope so that the table
       
   340 	 * definition has access to private methods.
       
   341 	 */
       
   342 	static const FunctionPtr iJumpTable[];
       
   343 	
       
   344 private:
       
   345 	//////////////
       
   346 	// This section describes the Clock component's Timer Control
       
   347 	//////////////
       
   348 
       
   349 	/**
       
   350 	 * Holds the current Wall Clock. The duration of a 'tick' is platform specific.
       
   351 	 * This needs to be 4-byte aligned to allow for atomic access.
       
   352 	 */
       
   353 	OMX_TICKS iWallTicks;
       
   354 	
       
   355 	/**
       
   356 	 * Encapsulates the relationship between wall time and media time.
       
   357 	 */
       
   358 	TMediaTimeContext iMtc;
       
   359 	
       
   360 	// conversion factors from wall 'ticks' to microseconds
       
   361 	TInt iMicroConvNum;
       
   362 	TInt iMicroConvDen;
       
   363 	TInt iMicroConvShift;
       
   364 	
       
   365 	// maximum time between calls to WallTime() - avoids 32-bit counter overflow
       
   366 	TInt iHeartbeatTimerInterval;
       
   367 	
       
   368 	// on some platforms User::FastCounter() counts backwards
       
   369 	TBool iSystemClockReversed;
       
   370 	
       
   371 private:
       
   372 	//////////////
       
   373 	// This section describes the Clock component's thread and other resources
       
   374 	//////////////
       
   375 
       
   376 	/**
       
   377 	 * This Clock component object needs to run in a high priority thread as it 
       
   378 	 * represents the OMX component timings
       
   379 	 */
       
   380 	RThread iThread;
       
   381 	
       
   382 	/**
       
   383 	 * Thread access control Mutex, 
       
   384 	 * used to control updating of the components requests by mutiple threads
       
   385 	 */
       
   386 	RMutex iQueMutex;
       
   387 
       
   388 	/**
       
   389 	 * Event timer to wake up this object to complete fulfillment of a request
       
   390 	 * This handle belongs to the High-Pri thread
       
   391 	 */
       
   392 	RTimer iTimer;
       
   393 	
       
   394 	/**
       
   395 	 * Flags to control timing thread exit/destroy.
       
   396 	 */
       
   397 	TBool iThreadStarted;
       
   398 	TBool iThreadRunning;
       
   399 	
       
   400 	/**
       
   401 	 * Complete this status on the timing thread to interrupt the timer sleep.
       
   402 	 * Timer itself can't be cancelled since timer handle is local to timing
       
   403 	 * thread.
       
   404 	 */
       
   405 	TRequestStatus iCancelStatus;
       
   406 
       
   407 private:
       
   408 	//////////////
       
   409 	// This section describes the Clock component's request management 
       
   410 	// infrastructure
       
   411 	//////////////
       
   412 
       
   413 	/**
       
   414 	 * Pending Media Time Requests
       
   415 	 */
       
   416 	TRequestDeltaQue iPendingRequestQue;
       
   417 
       
   418 	/**
       
   419 	 * The free queue header.
       
   420 	 * Items ared remove from here and placed on the pending queue.
       
   421 	 */
       
   422 	TRequestDeltaQue iFreeRequestQue;
       
   423 
       
   424 	/**
       
   425 	 * memory block where request list nodes are allocated
       
   426 	 */
       
   427 	TMediaRequest* iRequestBlock;
       
   428 
       
   429 	/**
       
   430 	 * Max number of request list nodes allocated
       
   431 	 */
       
   432 	const TUint iMaxRequests;
       
   433 	
       
   434 	COmxILClockProcessingFunction& iProcessingFunction;
       
   435 	}; // class CClockSupervisor
       
   436 
       
   437 
       
   438 #endif // CLOCKSUPERVISOR_H_