--- /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_