omxil/video/omxilclock/inc/clocksupervisor.h
branchOpenMAX-IL_SHAI
changeset 16 eedf2dcd43c6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omxil/video/omxilclock/inc/clocksupervisor.h	Fri May 07 16:25:23 2010 +0100
@@ -0,0 +1,438 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#ifndef CLOCKSUPERVISOR_H_
+#define CLOCKSUPERVISOR_H_
+
+#include <e32base.h>
+#include <openmax/il/khronos/v1_x/OMX_Other.h>
+
+/**
+ @file
+ @internalComponent
+ */
+
+// forward declaration as supervisor calls back to processing function
+class COmxILClockProcessingFunction;
+
+///////////////////////////////////////////////////////////////////////////////
+// List of structures declared in this file:
+// 
+// TMediaRequest
+// TEntryPoint
+// TIndexToFunctionMapping
+// CClockSupervisor
+// 
+///////////////////////////////////////////////////////////////////////////////
+// Storage of Clock requests.
+//
+// The Media Update storage holds a number of request updates to send to 
+// clients.
+// The updates are entered in a queue based on the delta of the 
+// 'expected MediaTime minus Offset' giving an absolute time (the delta). 
+// This difference is then calculated by the queue implementation on insertion
+// of the element.
+//
+// When the clock changes state it notifies the clients by sending them a state 
+// change notification broadcast.
+// The important thing to note here is that there is no seperate queue for 
+// outgoing notifications.
+// As soon as a request timer expires that request is forwarded. 
+// Broadcast requests are raised and placed first on the queue so are sent 
+// as and when they occur.
+//
+// When the scale is a change of direction (i.e. playing in the backwards 
+// direction), the queue is cleared and the delta's absolute value is taken.
+// 
+// The delta is a TInt which matches the Ticks datatype returned by the system.
+// 
+// We do not expect the phone to be in operation beyond the maximum duration 
+// held by the 64-bit Wall clock. Behaviour beyond this is undefined.
+//
+// The reason for choosing a list over an array is mainly access efficiency.
+//
+// 1) The insertions must be in order so as to be pulled off quickly.
+//    Updates are pulled off from the front of the queue, so you would have 
+//    to adjust the whole array each time.
+// 2) Updates arrive at different times and can expect to be fulfilled prior 
+//    to earlier updates, again the list would need to be adjusted after the 
+//    point of insertion.
+// 
+// Clients are attached via ports and the notifications are sent to them via 
+// these ports
+//
+///////////////////////////////////////////////////////////////////////////////
+// Clock functionality is invoked both externally & internally.
+//
+// Based on the OMX IL 1.1.1 standard, we route these incoming external 
+// requests to their relevant behaviour.
+//
+// This Clock component is intended to be created per use case.
+// That is for every use case that requires synchronisation.
+// This could result in several clocks being created, each with an audio and/or
+// video as an input, and each with a high-priority clock thread.
+// At most it is considered that there should only be a few of these components
+// in existance at any one time, as mobile devices should not really require it.
+// However, saying this, it should be factored into the design. 
+// At this stage it is envisioned that any clock component should reduce its 
+// timer events to once at just after the 32-bit wraparound when its 
+// application is not in focus. 
+// This is due to the time being reported to us in a 32-bit value, whilst our 
+// Wall clock is 64-bits. 
+// To avoid any wraparound and losing time by not regulary updating the upper 
+// word of our wall clock, we need to somehow check the system clock at this 
+// inteval. This is not a problem during normal operation but can be when the 
+// application is Paused or goes out of focus.
+//
+// NOTE: Assumes OMX_SKIP64BIT is not set when building OMX CORE
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * 
+ *
+ */
+class TMediaRequest
+	{
+public:
+	TInt64 iMediaTime;
+	TInt64 iOffset;
+	TInt64 iTriggerWallTime;		// == iWallTimeAtMediaTime - iOffset
+	TInt iPortIndex;
+	TAny* iClientPrivate;
+	
+	inline void Deque();
+	inline void AddBefore(TMediaRequest*);
+	
+public:
+	TMediaRequest *iPrev;
+	TMediaRequest *iNext;
+	};
+
+/**
+ * 
+ *
+ */
+class TMediaTimeContext
+	{
+public:
+	TMediaTimeContext(): iScaleQ16 (1 << 16), iInverseScaleQ16 (1 << 16)
+		{/*do nothing*/};
+
+	void SetScaleQ16(TInt32 aScaleQ16, TInt64 aWallTimeNow);
+public:
+	TInt64 iWallTimeBase;
+	TInt64 iMediaTimeBase;
+	
+	/**
+	 * Scale ranges map to modes of playback.
+	 * A Q16 value relative to a 1X forward advancement of the media clock.
+	 */
+	TInt32 iScaleQ16;
+	
+	/**
+	 * The reciprocal of iScaleQ16 (i.e. 1 / iScaleQ16), but adjusted for the
+	 * Q16 format.
+	 * 
+	 * It therefore has the value 2^32 / iScaleQ16.
+	 * 
+	 * If iScaleQ16 == 0, this field takes the value KMaxTInt (2^31 - 1)
+	 * 
+	 * If magnitude of iInverseScaleQ16 would be too large for a signed 32-bit
+	 * value, the value is clipped to KMaxTInt or KMinTInt (-2^31 or
+	 * (2^31 - 1)). This can only happen if iScaleQ16 == +/- 1.
+	 */
+	TInt32 iInverseScaleQ16;
+	};
+
+/**
+ * 
+ *
+ */
+class TRequestDeltaQue
+	{
+public:
+	TRequestDeltaQue();
+	
+	void Add(TMediaRequest* aElement, TInt64 aDelta);
+	TMediaRequest* RemoveFirst();
+	TBool FirstDelta(TInt64& aDelta) const;
+	void RecalculateAndReorder(TMediaTimeContext& aMTC);
+	TBool IsEmpty() const;
+	TUint Count() const;
+	
+private:
+	TBool InsertBeforeFoundPosition(TInt64 aDelta, TMediaRequest*& aItem) const;
+
+#ifdef _DEBUG
+	void DbgCheck() const;
+#endif
+#ifdef _OMXIL_COMMON_DEBUG_TRACING_ON
+	void DbgPrint() const;
+#endif
+
+private:
+	TMediaRequest* iHead;
+	TInt iCount;
+	};
+
+
+/**
+ * 
+ *
+ */
+class CClockSupervisor : public CBase
+	{
+public:
+#ifdef STABILITY_TEST_WRAPPER
+	friend class CStabilityTestWrapper;
+	friend class CStabilityTestNegativeWrapper;
+#endif
+friend class CClockThreadNotifier;	
+public:
+	static CClockSupervisor* NewL(COmxILClockProcessingFunction& aCallbacks);
+	~CClockSupervisor();
+
+	/**
+	 * Defines how a request arrived at the clock component
+	 */
+	enum TEntryPoint
+		{
+		EGetConfig,
+		ESetConfig
+		};
+	
+	// Producer function
+	// Invoked via clients of this component, i.e. GetConfig() and SetConfig()
+	OMX_ERRORTYPE ProduceRequest(OMX_INDEXTYPE aIndex, TEntryPoint aEntryPoint,
+								 TAny* aPassedStructPtr);
+								 
+	const OMX_TIME_CONFIG_CLOCKSTATETYPE GetMediaClockState() const
+		{
+		return iMediaClockState;
+		}
+
+private:
+	CClockSupervisor(COmxILClockProcessingFunction& aProcessingFunction);
+	void ConstructL();
+
+private:
+	//////////////
+	// This section describes the Clock thread related functions
+	//////////////
+	
+	// The timing thread's entry point
+	static TInt ThreadEntryPoint(TAny* aPtr);
+	void RunTimingThreadL();
+	
+private:
+	//////////////
+	// This section describes the request handler functions
+	//////////////
+
+	// From the Audio/Video feeds
+	OMX_ERRORTYPE HandleUpdateAudioReference(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+	OMX_ERRORTYPE HandleUpdateVideoReference(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+	
+	// From the OMX component
+	OMX_ERRORTYPE HandleSetPortClientStartTime(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+	OMX_ERRORTYPE HandleSubmitMediaTimeRequest(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+
+	// From the IL client
+	OMX_ERRORTYPE HandleGetSetTimeScale(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+	OMX_ERRORTYPE HandleGetSetSeekMode(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+	OMX_ERRORTYPE HandleGetSetClockState(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+	OMX_ERRORTYPE HandleGetSetActiveRefClock(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+
+	// Called from either IL client or IL components
+	OMX_ERRORTYPE HandleQueryCurrentWallTime(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+	OMX_ERRORTYPE HandleQueryCurrentMediaTime(TEntryPoint aEntry, OMX_PTR aPassedStructPtr);
+	
+private:
+	//////////////
+	// This section describes the Clock components internal house-keeping 
+	// routines
+	//////////////
+
+	// Perform actions related to placing the clock into the Stopped state
+	void DoTransitionToStoppedState();
+	
+	// Perform actions related to placing the clock into the Running state
+	void DoTransitionToRunningState();
+	
+	// Perform actions related to placing the clock into the Waiting state
+	void DoTransitionToWaitingState(OMX_U32 nWaitMask);
+	
+	// Update the tick counter, generating higher 32 bits
+	void UpdateWallTicks();
+	
+	// Consumer function
+	// Invoked at initialisation and runs in event loop.
+	TInt ConsumeRequests();
+	
+	// The timer loop to enable us to wake up on heart beat or requests
+	void TimerLoop();
+
+	// obtains the most appropriate start time based on scale (direction)
+	void CalculateStartTime();
+	
+	// reports whether all clients have reported their start times
+	TBool AllStartTimesReported();
+	
+	TInt64 WallTime();
+	
+	void UpdateMediaTime(TInt64 aMediaTime);
+	void BroadcastUpdate(const OMX_TIME_MEDIATIMETYPE& aUpdate);
+	
+	// reports error when clock thread panics
+	
+	void ReportClockThreadPanic();
+	
+private:
+	//////////////
+	// This section describes the clock's miscellaneous structures
+	//////////////
+
+	/**
+	 * State of the clock component's media clock:
+	 */
+	OMX_TIME_CONFIG_CLOCKSTATETYPE iMediaClockState;
+
+	/**
+	 * Choice of the clock component's reference clock:
+	 */
+	OMX_TIME_REFCLOCKTYPE iActiveRefClock;
+	
+	/**
+	 * Array of clients' start times:
+	 */
+	RArray<TInt64> iStartTimes;
+	TUint iStartTimesSet;			/* bit mask representing which elements of
+	                                   the start time array are valid */
+
+private:
+	//////////////
+	// This section describes the Clock component's routing structures
+	//////////////
+	
+	/*
+	 * typedef for function to handle incoming requests
+	 */
+	typedef OMX_ERRORTYPE (CClockSupervisor::*FunctionPtr)(TEntryPoint, OMX_PTR);
+
+	/*
+	 * Function jump table. Note that this is declared in class scope so that the table
+	 * definition has access to private methods.
+	 */
+	static const FunctionPtr iJumpTable[];
+	
+private:
+	//////////////
+	// This section describes the Clock component's Timer Control
+	//////////////
+
+	/**
+	 * Holds the current Wall Clock. The duration of a 'tick' is platform specific.
+	 * This needs to be 4-byte aligned to allow for atomic access.
+	 */
+	OMX_TICKS iWallTicks;
+	
+	/**
+	 * Encapsulates the relationship between wall time and media time.
+	 */
+	TMediaTimeContext iMtc;
+	
+	// conversion factors from wall 'ticks' to microseconds
+	TInt iMicroConvNum;
+	TInt iMicroConvDen;
+	TInt iMicroConvShift;
+	
+	// maximum time between calls to WallTime() - avoids 32-bit counter overflow
+	TInt iHeartbeatTimerInterval;
+	
+	// on some platforms User::FastCounter() counts backwards
+	TBool iSystemClockReversed;
+	
+private:
+	//////////////
+	// This section describes the Clock component's thread and other resources
+	//////////////
+
+	/**
+	 * This Clock component object needs to run in a high priority thread as it 
+	 * represents the OMX component timings
+	 */
+	RThread iThread;
+	
+	/**
+	 * Thread access control Mutex, 
+	 * used to control updating of the components requests by mutiple threads
+	 */
+	RMutex iQueMutex;
+
+	/**
+	 * Event timer to wake up this object to complete fulfillment of a request
+	 * This handle belongs to the High-Pri thread
+	 */
+	RTimer iTimer;
+	
+	/**
+	 * Flags to control timing thread exit/destroy.
+	 */
+	TBool iThreadStarted;
+	TBool iThreadRunning;
+	
+	/**
+	 * Complete this status on the timing thread to interrupt the timer sleep.
+	 * Timer itself can't be cancelled since timer handle is local to timing
+	 * thread.
+	 */
+	TRequestStatus iCancelStatus;
+
+private:
+	//////////////
+	// This section describes the Clock component's request management 
+	// infrastructure
+	//////////////
+
+	/**
+	 * Pending Media Time Requests
+	 */
+	TRequestDeltaQue iPendingRequestQue;
+
+	/**
+	 * The free queue header.
+	 * Items ared remove from here and placed on the pending queue.
+	 */
+	TRequestDeltaQue iFreeRequestQue;
+
+	/**
+	 * memory block where request list nodes are allocated
+	 */
+	TMediaRequest* iRequestBlock;
+
+	/**
+	 * Max number of request list nodes allocated
+	 */
+	const TUint iMaxRequests;
+	
+	COmxILClockProcessingFunction& iProcessingFunction;
+	}; // class CClockSupervisor
+
+
+#endif // CLOCKSUPERVISOR_H_