diff -r f429a0a2075b -r 735348f59235 mmdevicefw/mdf/src/audio/mdasoundadapter/mdasoundadapterbody.h --- 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 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 iFreePlayers; + RFifo 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