mmdevicefw/mdf/src/audio/mdasoundadapter/mdasoundadapterbody.h
branchRCL_3
changeset 49 735348f59235
parent 0 40261b775718
child 50 948c7f65f6d4
--- a/mmdevicefw/mdf/src/audio/mdasoundadapter/mdasoundadapterbody.h	Thu Aug 19 11:23:35 2010 +0300
+++ b/mmdevicefw/mdf/src/audio/mdasoundadapter/mdasoundadapterbody.h	Tue Aug 31 16:43:06 2010 +0300
@@ -29,6 +29,10 @@
 	{
 	EDeviceNotOpened,
 	EPanicPartialBufferConverterNotSupported,
+	EBadState,
+	ENoClientPlayRequest,
+	EFifoEmpty,
+	EFifoFull
 	};
 	
 //Structure used to map samples per second to the corresponding enums in RSoundSc
@@ -321,23 +325,28 @@
 							{255,254}
 						};
 
-//Total Number of sample rates
-const TInt KNumSampleRates = 9;
-//Number of shared chunk buffers used for playing
-const TInt KPlayMaxSharedChunkBuffers = 2;
-const TInt KPlayMaxSharedChunkBuffersMask = KPlayMaxSharedChunkBuffers-1; // use for % KPlayMaxSharedChunkBuffers
+// Total Number of sample rates
+const TUint KNumSampleRates = 9;
+// Number of shared chunk buffers used for playing
+// Each buffer is permanently mapped, via an index number, to a particular buffer in the chunk
+// The esoundsc.ldd can only handle a max of 8 pending play requests, therefore no point in having
+// more than 8 play buffers...
+const TUint KPlaySharedChunkBuffers = 8;
+// Size of RSoundSc play buffers
+const TUint KPlaySharedChunkBufferSize = 4096;
+
 //Number of shared chunk buffers used for recording
-const TInt KRecordMaxSharedChunkBuffers = 3;
-//we need to two players for playing and one is sufficient for recording
-const TInt KNumPlayers = 2;
-const TInt KNumPlayersMask = KNumPlayers-1; // & KNumPlayersMask is equiv to % KNumPlayers
+const TUint KRecordMaxSharedChunkBuffers = 8;
+// Size of RSoundSc record buffers
+const TUint KRecordSharedChunkBufferSize = 4096;
+
 //Shared chunk driver does not support max. buffer size. 16K is given in order to simulate the old driver behavior.
-const TInt KMaxBufferSize = 0x4000;
+const TUint KMaxBufferSize = 0x4000;
 
 class TPlaySharedChunkBufConfig : public TSharedChunkBufConfigBase
 	{
 public:
-	TInt iBufferOffsetList[KPlayMaxSharedChunkBuffers];
+	TInt iBufferOffsetList[KPlaySharedChunkBuffers];
 	};
 
 class TRecordSharedChunkBufConfig : public TSharedChunkBufConfigBase
@@ -348,6 +357,83 @@
 	
 class CChannelAndSampleRateConverter; // forward dec
 
+GLDEF_C void Panic(TSoundAdapterPanicCodes aPanicCode);//forward declaration
+
+// RFifo class which manages a fifo of up to COUNT items of type T
+template<typename T, TUint32 COUNT> class RFifo
+	{
+public:
+	RFifo()
+		: iWriteIndex(0), iReadIndex(0)
+		{}
+	TBool IsEmpty() const
+		{
+		return iWriteIndex == iReadIndex;
+		}
+	TBool IsFull() const
+		{
+		// Full if writing one more item would make iWriteIndex equal to iReadIndex
+		TUint32 next = NextIndex(iWriteIndex);
+		return next == iReadIndex;
+		}
+	/// Push item into FIFO. Does not take ownership. Will PANIC with EFifoFull if full.
+	void Push(const T &aItem)
+		{
+		if(IsFull())
+			{
+			Panic(EFifoFull);
+			}
+		iFifo[iWriteIndex] = aItem;
+		iWriteIndex = NextIndex(iWriteIndex);
+		}
+    /// Pop item from FIFO. Will PANIC with EFifoEmpty if empty 
+	T Pop()
+		{
+		if(IsEmpty())
+			{
+			Panic(EFifoEmpty);
+			}
+		TUint32 tmp = iReadIndex;
+		iReadIndex = NextIndex(iReadIndex);
+		return iFifo[tmp];
+		}
+
+    /// Peek first item from FIFO. Will PANIC with EFifoEmpty if empty 
+	T Peek()
+		{
+		if(IsEmpty())
+			{
+			Panic(EFifoEmpty);
+			}
+		return iFifo[iReadIndex];
+		}
+	TUint Length() const
+		{
+		TUint len;
+		if(iWriteIndex >= iReadIndex)
+			{
+			len = iWriteIndex - iReadIndex;
+			}
+		else
+			{
+			len =  COUNT+1 - (iReadIndex - iWriteIndex);
+			}
+		return len;
+		}
+private:
+	TUint32 NextIndex(TUint32 aIndex) const
+		{
+		++aIndex;
+		aIndex %= (COUNT+1);
+		return aIndex;
+		}
+	T iFifo[COUNT+1];
+	TUint32 iWriteIndex;
+	TUint32 iReadIndex;
+	};
+
+
+
 //Body class for the adapter
 NONSHARABLE_CLASS( RMdaDevSound::CBody ): public CBase
 	{
@@ -361,27 +447,58 @@
 		void RunL();
 		TInt RunError(TInt aError);
 		void DoCancel();
+		void PlayData(TUint aChunkOffset, TInt aLength);
+
+		TUint GetPlayerIndex() const;
+
+	private:		
+		RMdaDevSound::CBody& iParent;
+		const TUint iIndex; // index of this object in parent
+		
+		TInt iBufferOffset;
+		TInt iBufferLength;
+		};
+
+	
+	NONSHARABLE_CLASS( CRecorder ) : public CActive
+		{
+	public:
+		explicit CRecorder(TInt aPriority, RMdaDevSound::CBody& aParent);
+		~CRecorder();
+		void RunL();
+		TInt RunError(TInt aError);
+		void DoCancel();
 		void RecordData(TInt& aLength);
-		void PlayData(TInt aBufferOffset, TInt aBufferLength);
-		void Stop();
-		void ResetPlayer();
-		void PlaySoundDevice();
-	private:
+
+	private:		
 		RMdaDevSound::CBody& iParent;
-		const TInt iIndex; // index of this object in parent
-		TBool iRequestPending;
+
 		TInt iBufferOffset;
 		TInt iBufferLength;
 		};
 	
-	enum TState
+	enum TStateEnum
 		{
 		ENotReady,
-		EOpened,
-		EPlaying,
+		EStopped,
 		ERecording,
-		EPlayBuffersFlushed,
-		EPaused
+		ERecordingPausedInHw,
+		ERecordingPausedInSw,
+		EPlaying,
+		EPlayingPausedInHw, // ie. Play request pending on h/w and paused
+		EPlayingPausedInSw, // ie. Driver not playing or paused
+		EPlayingUnderrun
+		};
+
+	NONSHARABLE_CLASS( TState )
+		{
+		public:
+			TState(TStateEnum aState) : iState(aState) {}
+			const TText8 *Name() const;
+			TState &operator=(TStateEnum aNewState);
+			operator TStateEnum() const { return iState; }
+		private:
+			TStateEnum iState;
 		};
 		
 	class TFormatData
@@ -442,40 +559,55 @@
 	
 	//for players
 	void SoundDeviceError(TInt aError);
-	void SoundDeviceError(TInt aError, TInt aPlayerIndex);
 	RSoundSc& PlaySoundDevice();
 	RSoundSc& RecordSoundDevice();
-	TState State();
+	const TState &State() const;
 	void BufferFilled(TInt aError);
-	void BufferEmptied();
-	void PlayCancelled();
-	void UpdateTimeAndBytesPlayed();
-	TBool TimerActive();
-	TBool FlushCalledDuringPause();
+
+	// Called whenever a player becomes inactive.
+	// This includes driver request ok, driver request failed, CPlayer:::RunError invoked.
+	void PlayRequestHasCompleted(CPlayer *aPlayer, TInt aStatus, TBool aDueToCancelCommand);
 
 private:
 	CBody();
 	void ConstructL();
 	
 	TInt NegotiateFormat(const TCurrentSoundFormatBuf& aFormat, RSoundSc& aDevice, TFormatData &aFormatData);
+
+	void StartPlayersAndUpdateState();
+	void StartRecordRequest();
+
+	const char *StateName() const;
+
+	TBool InRecordMode() const;
+	TBool InPlayMode() const;
+
+	TUint32 CurrentTimeInMsec() const;
+	TUint64 BytesPlayed64();
+
 private:
 	RSoundSc iPlaySoundDevice;
+	RChunk iPlayChunk;//handle to the shared chunk
 	RSoundSc iRecordSoundDevice;
-	RChunk iChunk;//handle to the shared chunk
+	RChunk iRecordChunk;//handle to the shared chunk
 	TState iState;
-	CPlayer* iPlayers[KNumPlayers];//we need atleast two players for playing and one for recording
-	
+
 	//Playing Properties
-	TPlaySharedChunkBufConfig iBufferConfig;
-	TInt iBufferIndex;
-	TInt iCurrentPlayer;
+	TPlaySharedChunkBufConfig iPlayBufferConfig;
 	TInt iDeviceBufferLength;
+	
 	//Stores the status of CDataPathPlayer
-	TRequestStatus* iPlayerStatus;
+	TRequestStatus* iClientPlayStatus;
+	TPtrC8 iClientPlayData;
 	//Stores the status of CSoundDevPlayErrorReceiver
-	TRequestStatus* iPlayErrorStatus;
-	RBuf8 iBufferRemaining;
-	TBool iHaveSecondPhaseData;
+	TRequestStatus* iClientPlayErrorStatus;
+	RBuf8 iConvertedPlayData;
+	RBuf8 iSavedTrailingData;
+
+	CPlayer* iPlayers[KPlaySharedChunkBuffers];
+	RFifo<CPlayer *, KPlaySharedChunkBuffers> iFreePlayers;
+	RFifo<TUint32, KPlaySharedChunkBuffers> iActivePlayRequestSizes;
+	
 	TInt iRequestMinSize;
 	TUint iRequestMinMask;
 	
@@ -483,23 +615,25 @@
 	TRecordSharedChunkBufConfig iRecordBufferConfig;
 	TInt iBufferOffset;
 	TInt iBufferLength;
-	TPtrC8 iSecondPhaseData;
+
 	//Stores the status of CDataPathRecorder
-	TRequestStatus* iRecorderStatus;
+	TRequestStatus* iClientRecordStatus;
 	//Stores the status of CSoundDevRecordErrorReceiver
-	TRequestStatus* iRecordErrorStatus;
-	TDes8* iData;//stores the data pointer from datapath recorder
-	TInt iBytesPlayed;
-#ifdef SYMBIAN_SOUNDADAPTER_BYTESPLAYED
-	TInt iFCFrequency;
+	TRequestStatus* iClientRecordErrorStatus;
+	TDes8* iClientRecordData;//stores the data pointer from datapath recorder
+	RBuf8 iBufferedRecordData; // Used if RSoundSc returns more data than current client request requires.
+
+	CRecorder* iRecorder; // We only need one recorder. The driver will buffer data for us.
+
+	TBool iUnderFlowReportedSinceLastPlayOrRecordRequest;
+	
+	TUint64 iBytesPlayed;
+	TUint32 iNTickPeriodInUsec;
+	TUint32 iStartTime; // Time when previous driver PlayData completed (or first was issued) in msec
+	TUint32 iPauseTime; // Time when pause started in msec
+	TUint64 iPausedBytesPlayed;
+
+	TFormatData iPlayFormatData;
+	TFormatData iRecordFormatData;
+	};
 #endif
-	TUint32 iStartTime;
-	TBool iTimerActive;
-	TBool iFlushCalledDuringPause;
-	TBool iPauseDeviceDriverOnNewData;
-
-	TFormatData iPlayData;
-	TFormatData iRecordData;
-	};
-GLDEF_C void Panic(TSoundAdapterPanicCodes aPanicCode);//forward declaration
-#endif