sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #ifndef MDASOUNDADAPTERBODY_H sl@0: #define MDASOUNDADAPTERBODY_H sl@0: sl@0: #include "mdasoundadapter.h" sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: /** sl@0: Panic category and codes for the mdasoundadapter sl@0: */ sl@0: _LIT(KSoundAdapterPanicCategory, "mdasoundadapter"); sl@0: enum TSoundAdapterPanicCodes sl@0: { sl@0: EDeviceNotOpened, sl@0: EPanicPartialBufferConverterNotSupported, sl@0: EBadState, sl@0: ENoClientPlayRequest, sl@0: EFifoEmpty, sl@0: EFifoFull sl@0: }; sl@0: sl@0: //Structure used to map samples per second to the corresponding enums in RSoundSc sl@0: struct TSampleRateEnumTable sl@0: { sl@0: TInt iRate; sl@0: TSoundRate iRateEnum; sl@0: TUint iRateConstant; sl@0: }; sl@0: sl@0: //Table that maps given samples per second to the corresponding enums in RSoundSc sl@0: const TSampleRateEnumTable KRateEnumLookup[] = sl@0: { sl@0: {48000,ESoundRate48000Hz,KSoundRate48000Hz}, sl@0: {44100,ESoundRate44100Hz,KSoundRate44100Hz}, sl@0: {32000,ESoundRate32000Hz,KSoundRate32000Hz}, sl@0: {24000,ESoundRate24000Hz,KSoundRate24000Hz}, sl@0: {22050,ESoundRate22050Hz,KSoundRate22050Hz}, sl@0: {16000,ESoundRate16000Hz,KSoundRate16000Hz}, sl@0: {12000,ESoundRate12000Hz,KSoundRate12000Hz}, sl@0: {11025,ESoundRate11025Hz,KSoundRate11025Hz}, sl@0: {8000, ESoundRate8000Hz, KSoundRate8000Hz} sl@0: }; sl@0: //Structure used to map linear value of the volume to the decibel value. sl@0: struct TLinearToDbTable sl@0: { sl@0: TInt iLiniearValue; sl@0: TInt iDBValue; sl@0: }; sl@0: sl@0: sl@0: //Table that maps given linear value of volume to the corresponding decibel value. sl@0: const TLinearToDbTable KLinerToDbConstantLookup[] = sl@0: { sl@0: {0,0}, sl@0: {1,158}, sl@0: {2,170}, sl@0: {3,177}, sl@0: {4,182}, sl@0: {5,186}, sl@0: {6,189}, sl@0: {7,192}, sl@0: {8,194}, sl@0: {9,196}, sl@0: {10,198}, sl@0: {11,200}, sl@0: {12,201}, sl@0: {13,203}, sl@0: {14,204}, sl@0: {15,205}, sl@0: {16,206}, sl@0: {17,207}, sl@0: {18,208}, sl@0: {19,209}, sl@0: {20,210}, sl@0: {21,211}, sl@0: {22,212}, sl@0: {23,213}, sl@0: {24,213}, sl@0: {25,214}, sl@0: {26,215}, sl@0: {27,215}, sl@0: {28,216}, sl@0: {29,217}, sl@0: {30,217}, sl@0: {31,218}, sl@0: {32,218}, sl@0: {33,219}, sl@0: {34,219}, sl@0: {35,220}, sl@0: {36,220}, sl@0: {37,221}, sl@0: {38,221}, sl@0: {39,222}, sl@0: {40,222}, sl@0: {41,223}, sl@0: {42,223}, sl@0: {43,224}, sl@0: {44,224}, sl@0: {45,224}, sl@0: {46,225}, sl@0: {47,225}, sl@0: {48,225}, sl@0: {49,226}, sl@0: {50,226}, sl@0: {51,226}, sl@0: {52,227}, sl@0: {53,227}, sl@0: {54,227}, sl@0: {55,228}, sl@0: {56,228}, sl@0: {57,228}, sl@0: {58,229}, sl@0: {59,229}, sl@0: {60,229}, sl@0: {61,230}, sl@0: {62,230}, sl@0: {63,230}, sl@0: {64,230}, sl@0: {65,231}, sl@0: {66,231}, sl@0: {67,231}, sl@0: {68,231}, sl@0: {69,232}, sl@0: {70,232}, sl@0: {71,232}, sl@0: {72,232}, sl@0: {73,233}, sl@0: {74,233}, sl@0: {75,233}, sl@0: {76,233}, sl@0: {77,234}, sl@0: {78,234}, sl@0: {79,234}, sl@0: {80,234}, sl@0: {81,235}, sl@0: {82,235}, sl@0: {83,235}, sl@0: {84,235}, sl@0: {85,235}, sl@0: {86,236}, sl@0: {87,236}, sl@0: {88,236}, sl@0: {89,236}, sl@0: {90,236}, sl@0: {91,237}, sl@0: {92,237}, sl@0: {93,237}, sl@0: {94,237}, sl@0: {95,237}, sl@0: {96,237}, sl@0: {97,238}, sl@0: {98,238}, sl@0: {99,238}, sl@0: {100,238}, sl@0: {101,238}, sl@0: {102,239}, sl@0: {103,239}, sl@0: {104,239}, sl@0: {105,239}, sl@0: {106,239}, sl@0: {107,239}, sl@0: {108,240}, sl@0: {109,240}, sl@0: {110,240}, sl@0: {111,240}, sl@0: {112,240}, sl@0: {113,240}, sl@0: {114,240}, sl@0: {115,241}, sl@0: {116,241}, sl@0: {117,241}, sl@0: {118,241}, sl@0: {119,241}, sl@0: {120,241}, sl@0: {121,241}, sl@0: {122,242}, sl@0: {123,242}, sl@0: {124,242}, sl@0: {125,242}, sl@0: {126,242}, sl@0: {127,242}, sl@0: {128,242}, sl@0: {129,243}, sl@0: {130,243}, sl@0: {131,243}, sl@0: {132,243}, sl@0: {133,243}, sl@0: {134,243}, sl@0: {135,243}, sl@0: {136,244}, sl@0: {137,244}, sl@0: {138,244}, sl@0: {139,244}, sl@0: {140,244}, sl@0: {141,244}, sl@0: {142,244}, sl@0: {143,244}, sl@0: {144,245}, sl@0: {145,245}, sl@0: {146,245}, sl@0: {147,245}, sl@0: {148,245}, sl@0: {149,245}, sl@0: {150,245}, sl@0: {151,245}, sl@0: {152,245}, sl@0: {153,246}, sl@0: {154,246}, sl@0: {155,246}, sl@0: {156,246}, sl@0: {157,246}, sl@0: {158,246}, sl@0: {159,246}, sl@0: {160,246}, sl@0: {161,246}, sl@0: {162,247}, sl@0: {163,247}, sl@0: {164,247}, sl@0: {165,247}, sl@0: {166,247}, sl@0: {167,247}, sl@0: {168,247}, sl@0: {169,247}, sl@0: {170,247}, sl@0: {171,247}, sl@0: {172,248}, sl@0: {173,248}, sl@0: {174,248}, sl@0: {175,248}, sl@0: {176,248}, sl@0: {177,248}, sl@0: {178,248}, sl@0: {179,248}, sl@0: {180,248}, sl@0: {181,248}, sl@0: {182,249}, sl@0: {183,249}, sl@0: {184,249}, sl@0: {185,249}, sl@0: {186,249}, sl@0: {187,249}, sl@0: {188,249}, sl@0: {189,249}, sl@0: {190,249}, sl@0: {191,249}, sl@0: {192,250}, sl@0: {193,250}, sl@0: {194,250}, sl@0: {195,250}, sl@0: {196,250}, sl@0: {197,250}, sl@0: {198,250}, sl@0: {199,250}, sl@0: {200,250}, sl@0: {201,250}, sl@0: {202,250}, sl@0: {203,250}, sl@0: {204,251}, sl@0: {205,251}, sl@0: {206,251}, sl@0: {207,251}, sl@0: {208,251}, sl@0: {209,251}, sl@0: {210,251}, sl@0: {211,251}, sl@0: {212,251}, sl@0: {213,251}, sl@0: {214,251}, sl@0: {215,251}, sl@0: {216,252}, sl@0: {217,252}, sl@0: {218,252}, sl@0: {219,252}, sl@0: {220,252}, sl@0: {221,252}, sl@0: {222,252}, sl@0: {223,252}, sl@0: {224,252}, sl@0: {225,252}, sl@0: {226,252}, sl@0: {227,252}, sl@0: {228,252}, sl@0: {229,253}, sl@0: {230,253}, sl@0: {231,253}, sl@0: {232,253}, sl@0: {233,253}, sl@0: {234,253}, sl@0: {235,253}, sl@0: {236,253}, sl@0: {237,253}, sl@0: {238,253}, sl@0: {239,253}, sl@0: {240,253}, sl@0: {241,253}, sl@0: {242,254}, sl@0: {243,254}, sl@0: {244,254}, sl@0: {245,254}, sl@0: {246,254}, sl@0: {247,254}, sl@0: {248,254}, sl@0: {249,254}, sl@0: {250,254}, sl@0: {251,254}, sl@0: {252,254}, sl@0: {253,254}, sl@0: {254,254}, sl@0: {255,254} sl@0: }; sl@0: sl@0: // Total Number of sample rates sl@0: const TUint KNumSampleRates = 9; sl@0: // Number of shared chunk buffers used for playing sl@0: // Each buffer is permanently mapped, via an index number, to a particular buffer in the chunk sl@0: // The esoundsc.ldd can only handle a max of 8 pending play requests, therefore no point in having sl@0: // more than 8 play buffers... sl@0: const TUint KPlaySharedChunkBuffers = 8; sl@0: // Size of RSoundSc play buffers sl@0: const TUint KPlaySharedChunkBufferSize = 4096; sl@0: sl@0: //Number of shared chunk buffers used for recording sl@0: const TUint KRecordMaxSharedChunkBuffers = 8; sl@0: // Size of RSoundSc record buffers sl@0: const TUint KRecordSharedChunkBufferSize = 4096; sl@0: sl@0: //Shared chunk driver does not support max. buffer size. 16K is given in order to simulate the old driver behavior. sl@0: const TUint KMaxBufferSize = 0x4000; sl@0: sl@0: class TPlaySharedChunkBufConfig : public TSharedChunkBufConfigBase sl@0: { sl@0: public: sl@0: TInt iBufferOffsetList[KPlaySharedChunkBuffers]; sl@0: }; sl@0: sl@0: class TRecordSharedChunkBufConfig : public TSharedChunkBufConfigBase sl@0: { sl@0: public: sl@0: TInt iBufferOffsetList[KRecordMaxSharedChunkBuffers]; sl@0: }; sl@0: sl@0: class CChannelAndSampleRateConverter; // forward dec sl@0: sl@0: GLDEF_C void Panic(TSoundAdapterPanicCodes aPanicCode);//forward declaration sl@0: sl@0: // RFifo class which manages a fifo of up to COUNT items of type T sl@0: template class RFifo sl@0: { sl@0: public: sl@0: RFifo() sl@0: : iWriteIndex(0), iReadIndex(0) sl@0: {} sl@0: TBool IsEmpty() const sl@0: { sl@0: return iWriteIndex == iReadIndex; sl@0: } sl@0: TBool IsFull() const sl@0: { sl@0: // Full if writing one more item would make iWriteIndex equal to iReadIndex sl@0: TUint32 next = NextIndex(iWriteIndex); sl@0: return next == iReadIndex; sl@0: } sl@0: /// Push item into FIFO. Does not take ownership. Will PANIC with EFifoFull if full. sl@0: void Push(const T &aItem) sl@0: { sl@0: if(IsFull()) sl@0: { sl@0: Panic(EFifoFull); sl@0: } sl@0: iFifo[iWriteIndex] = aItem; sl@0: iWriteIndex = NextIndex(iWriteIndex); sl@0: } sl@0: /// Pop item from FIFO. Will PANIC with EFifoEmpty if empty sl@0: T Pop() sl@0: { sl@0: if(IsEmpty()) sl@0: { sl@0: Panic(EFifoEmpty); sl@0: } sl@0: TUint32 tmp = iReadIndex; sl@0: iReadIndex = NextIndex(iReadIndex); sl@0: return iFifo[tmp]; sl@0: } sl@0: sl@0: /// Peek first item from FIFO. Will PANIC with EFifoEmpty if empty sl@0: T Peek() sl@0: { sl@0: if(IsEmpty()) sl@0: { sl@0: Panic(EFifoEmpty); sl@0: } sl@0: return iFifo[iReadIndex]; sl@0: } sl@0: TUint Length() const sl@0: { sl@0: TUint len; sl@0: if(iWriteIndex >= iReadIndex) sl@0: { sl@0: len = iWriteIndex - iReadIndex; sl@0: } sl@0: else sl@0: { sl@0: len = COUNT+1 - (iReadIndex - iWriteIndex); sl@0: } sl@0: return len; sl@0: } sl@0: private: sl@0: TUint32 NextIndex(TUint32 aIndex) const sl@0: { sl@0: ++aIndex; sl@0: aIndex %= (COUNT+1); sl@0: return aIndex; sl@0: } sl@0: T iFifo[COUNT+1]; sl@0: TUint32 iWriteIndex; sl@0: TUint32 iReadIndex; sl@0: }; sl@0: sl@0: sl@0: sl@0: //Body class for the adapter sl@0: NONSHARABLE_CLASS( RMdaDevSound::CBody ): public CBase sl@0: { sl@0: public: sl@0: //This class handles the play/record completions from the new sound driver sl@0: NONSHARABLE_CLASS( CPlayer ) : public CActive sl@0: { sl@0: public: sl@0: explicit CPlayer(TInt aPriority, RMdaDevSound::CBody& aParent, TInt aIndex); sl@0: ~CPlayer(); sl@0: void RunL(); sl@0: TInt RunError(TInt aError); sl@0: void DoCancel(); sl@0: void PlayData(TUint aChunkOffset, TInt aLength); sl@0: sl@0: TUint GetPlayerIndex() const; sl@0: sl@0: private: sl@0: RMdaDevSound::CBody& iParent; sl@0: const TUint iIndex; // index of this object in parent sl@0: sl@0: TInt iBufferOffset; sl@0: TInt iBufferLength; sl@0: }; sl@0: sl@0: sl@0: NONSHARABLE_CLASS( CRecorder ) : public CActive sl@0: { sl@0: public: sl@0: explicit CRecorder(TInt aPriority, RMdaDevSound::CBody& aParent); sl@0: ~CRecorder(); sl@0: void RunL(); sl@0: TInt RunError(TInt aError); sl@0: void DoCancel(); sl@0: void RecordData(TInt& aLength); sl@0: sl@0: private: sl@0: RMdaDevSound::CBody& iParent; sl@0: sl@0: TInt iBufferOffset; sl@0: TInt iBufferLength; sl@0: }; sl@0: sl@0: enum TStateEnum sl@0: { sl@0: ENotReady, sl@0: EStopped, sl@0: ERecording, sl@0: ERecordingPausedInHw, sl@0: ERecordingPausedInSw, sl@0: EPlaying, sl@0: EPlayingPausedInHw, // ie. Play request pending on h/w and paused sl@0: EPlayingPausedInSw, // ie. Driver not playing or paused sl@0: EPlayingUnderrun sl@0: }; sl@0: sl@0: NONSHARABLE_CLASS( TState ) sl@0: { sl@0: public: sl@0: TState(TStateEnum aState) : iState(aState) {} sl@0: const TText8 *Name() const; sl@0: TState &operator=(TStateEnum aNewState); sl@0: operator TStateEnum() const { return iState; } sl@0: private: sl@0: TStateEnum iState; sl@0: }; sl@0: sl@0: class TFormatData sl@0: { sl@0: public: sl@0: inline TFormatData(): sl@0: iSampleRate(8000), iRequestedChannels(1) // default sl@0: { sl@0: } sl@0: public: sl@0: CChannelAndSampleRateConverter* iConverter; sl@0: TInt iSampleRate; sl@0: TInt iActualRate; sl@0: TInt iRequestedChannels; sl@0: TInt iActualChannels; sl@0: }; sl@0: sl@0: public: sl@0: ~CBody(); sl@0: static CBody* NewL(); sl@0: TInt Open(TInt aUnit=KNullUnit); sl@0: TVersion VersionRequired() const; sl@0: TInt IsMdaSound(); sl@0: void PlayFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported); sl@0: void GetPlayFormat(TCurrentSoundFormatBuf& aFormat); sl@0: TInt SetPlayFormat(const TCurrentSoundFormatBuf& aFormat); sl@0: TInt PlayVolume(); sl@0: void SetPlayVolume(TInt aVolume); sl@0: void SetVolume(TInt aLogarithmicVolume); sl@0: void CancelPlayData(); sl@0: void RecordFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported); sl@0: void GetRecordFormat(TCurrentSoundFormatBuf& aFormat); sl@0: TInt SetRecordFormat(const TCurrentSoundFormatBuf& aFormat); sl@0: TInt RecordLevel(); sl@0: void SetRecordLevel(TInt aLevel); sl@0: void CancelRecordData(); sl@0: void FlushRecordBuffer(); sl@0: TInt BytesPlayed(); sl@0: void ResetBytesPlayed(); sl@0: void PausePlayBuffer(); sl@0: void ResumePlaying(); sl@0: void PauseRecordBuffer(); sl@0: void ResumeRecording(); sl@0: TInt GetTimePlayed(TTimeIntervalMicroSeconds& aTimePlayed); sl@0: void Close(); sl@0: TInt Handle(); sl@0: void PlayData(TRequestStatus& aStatus,const TDesC8& aData); sl@0: void RecordData(TRequestStatus& aStatus,TDes8& aData); sl@0: void NotifyRecordError(TRequestStatus& aStatus); sl@0: void NotifyPlayError(TRequestStatus& aStatus); sl@0: void CancelNotifyPlayError(); sl@0: void CancelNotifyRecordError(); sl@0: void FlushPlayBuffer(); sl@0: //internal methods added to reduce the code sl@0: void FormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported, RSoundSc& aDevice); sl@0: void GetFormat(TCurrentSoundFormatBuf& aFormat, RSoundSc& aDevice, const TFormatData &aFormatData); sl@0: TInt SetFormat(const TCurrentSoundFormatBuf& aFormat, RSoundSc& aDevice, TFormatData &aFormatData); sl@0: sl@0: //for players sl@0: void SoundDeviceError(TInt aError); sl@0: RSoundSc& PlaySoundDevice(); sl@0: RSoundSc& RecordSoundDevice(); sl@0: const TState &State() const; sl@0: void BufferFilled(TInt aError); sl@0: sl@0: // Called whenever a player becomes inactive. sl@0: // This includes driver request ok, driver request failed, CPlayer:::RunError invoked. sl@0: void PlayRequestHasCompleted(CPlayer *aPlayer, TInt aStatus, TBool aDueToCancelCommand); sl@0: sl@0: private: sl@0: CBody(); sl@0: void ConstructL(); sl@0: sl@0: TInt NegotiateFormat(const TCurrentSoundFormatBuf& aFormat, RSoundSc& aDevice, TFormatData &aFormatData); sl@0: sl@0: void StartPlayersAndUpdateState(); sl@0: void StartRecordRequest(); sl@0: sl@0: const char *StateName() const; sl@0: sl@0: TBool InRecordMode() const; sl@0: TBool InPlayMode() const; sl@0: sl@0: TUint32 CurrentTimeInMsec() const; sl@0: TUint64 BytesPlayed64(); sl@0: sl@0: private: sl@0: RSoundSc iPlaySoundDevice; sl@0: RChunk iPlayChunk;//handle to the shared chunk sl@0: RSoundSc iRecordSoundDevice; sl@0: RChunk iRecordChunk;//handle to the shared chunk sl@0: TState iState; sl@0: sl@0: //Playing Properties sl@0: TPlaySharedChunkBufConfig iPlayBufferConfig; sl@0: TInt iDeviceBufferLength; sl@0: sl@0: //Stores the status of CDataPathPlayer sl@0: TRequestStatus* iClientPlayStatus; sl@0: TPtrC8 iClientPlayData; sl@0: //Stores the status of CSoundDevPlayErrorReceiver sl@0: TRequestStatus* iClientPlayErrorStatus; sl@0: RBuf8 iConvertedPlayData; sl@0: RBuf8 iSavedTrailingData; sl@0: sl@0: CPlayer* iPlayers[KPlaySharedChunkBuffers]; sl@0: RFifo iFreePlayers; sl@0: RFifo iActivePlayRequestSizes; sl@0: sl@0: TInt iRequestMinSize; sl@0: TUint iRequestMinMask; sl@0: sl@0: //Recording Properties sl@0: TRecordSharedChunkBufConfig iRecordBufferConfig; sl@0: TInt iBufferOffset; sl@0: TInt iBufferLength; sl@0: sl@0: //Stores the status of CDataPathRecorder sl@0: TRequestStatus* iClientRecordStatus; sl@0: //Stores the status of CSoundDevRecordErrorReceiver sl@0: TRequestStatus* iClientRecordErrorStatus; sl@0: TDes8* iClientRecordData;//stores the data pointer from datapath recorder sl@0: RBuf8 iBufferedRecordData; // Used if RSoundSc returns more data than current client request requires. sl@0: sl@0: CRecorder* iRecorder; // We only need one recorder. The driver will buffer data for us. sl@0: sl@0: TBool iUnderFlowReportedSinceLastPlayOrRecordRequest; sl@0: sl@0: TUint64 iBytesPlayed; sl@0: TUint32 iNTickPeriodInUsec; sl@0: TUint32 iStartTime; // Time when previous driver PlayData completed (or first was issued) in msec sl@0: TUint32 iPauseTime; // Time when pause started in msec sl@0: TUint64 iPausedBytesPlayed; sl@0: sl@0: TFormatData iPlayFormatData; sl@0: TFormatData iRecordFormatData; sl@0: }; sl@0: #endif