sl@0: // Copyright (c) 2006-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: sl@0: sl@0: // INCLUDE FILES sl@0: #include "mmfdevsoundproxy.h" sl@0: #include "mmfdevsoundcallbackhandler.h" sl@0: #ifdef _DEBUG sl@0: #include sl@0: sl@0: #define SYMBIAN_DEBPRN0(str) RDebug::Print(str, this) sl@0: #define SYMBIAN_DEBPRN1(str, val1) RDebug::Print(str, this, val1) sl@0: #define SYMBIAN_DEBPRN2(str, val1, val2) RDebug::Print(str, this, val1, val2) sl@0: #else sl@0: #define SYMBIAN_DEBPRN0(str) sl@0: #define SYMBIAN_DEBPRN1(str, val1) sl@0: #define SYMBIAN_DEBPRN2(str, val1, val2) sl@0: #endif //_DEBUG sl@0: sl@0: // ============================ MEMBER FUNCTIONS ============================== sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::NewL sl@0: // Two-phased constructor. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: CMsgQueueHandler* CMsgQueueHandler::NewL( sl@0: RMMFDevSoundProxy* aDevSoundProxy, sl@0: MDevSoundObserver& aDevSoundObserver, sl@0: RMsgQueue* aMsgQueue, sl@0: MMMFDevSoundCustomInterfaceObserver& aDevSoundCIObserver) sl@0: { sl@0: CMsgQueueHandler* self = new(ELeave) CMsgQueueHandler(aDevSoundProxy, sl@0: aDevSoundObserver, sl@0: aMsgQueue, sl@0: aDevSoundCIObserver); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::CMsgQueueHandler sl@0: // C++ default constructor can NOT contain any code, that might leave. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: CMsgQueueHandler::CMsgQueueHandler (RMMFDevSoundProxy* aDevSoundProxy, sl@0: MDevSoundObserver& aDevSoundObserver, sl@0: RMsgQueue* aMsgQueue, sl@0: MMMFDevSoundCustomInterfaceObserver& aDevSoundCIObserver) sl@0: : CActive(EPriorityStandard), sl@0: iDevSoundProxy(aDevSoundProxy), sl@0: iDevSoundObserver(aDevSoundObserver), sl@0: iMsgQueue(aMsgQueue), sl@0: iChunkDataPtr(0, 0, 0), sl@0: iDevSoundCIObserver(aDevSoundCIObserver) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::ConstructL sl@0: // Symbian 2nd phase constructor can leave. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::ConstructL() sl@0: { sl@0: iEmptyBuffer = CMMFDescriptorBuffer::NewL(0); sl@0: iAsyncQueueFinish = new (ELeave) CAsyncCallBack(CActive::EPriorityStandard); sl@0: TCallBack asyncCallback(AsyncQueueFinishCallback, this); sl@0: iAsyncQueueFinish->Set(asyncCallback); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::~CMsgQueueHandler sl@0: // Destructor. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: CMsgQueueHandler::~CMsgQueueHandler() sl@0: { sl@0: Cancel(); sl@0: if ( iMsgQueue ) sl@0: { sl@0: iMsgQueue->Close(); sl@0: } sl@0: iChunk.Close(); sl@0: sl@0: delete iDataBuffer; sl@0: delete iEmptyBuffer; sl@0: delete iAsyncQueueFinish; sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::ReceiveEvents sl@0: // Subscribes for Play Error event from the DevSound server. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::ReceiveEvents() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::ReceiveEvents - Enter")); sl@0: if (!IsActive()) sl@0: { sl@0: iMsgQueue->NotifyDataAvailable(iStatus); sl@0: SetActive(); sl@0: } sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::ReceiveEvents - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::RunL sl@0: // Handles active object’s request completion event. sl@0: // sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::RunL() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::RunL - Enter")); sl@0: TInt err = iMsgQueue->Receive(iCurrentItem); sl@0: sl@0: if (err == KErrNone || err == KErrUnderflow) sl@0: { sl@0: // Signal that we're ready to process the next message sl@0: ReceiveEvents(); sl@0: } sl@0: sl@0: if (err == KErrNone) sl@0: { sl@0: switch (iCurrentItem.iRequest) sl@0: { sl@0: case EMMFDevSoundProxyICEvent: sl@0: { sl@0: DoInitComplete(); sl@0: break; sl@0: } sl@0: case EMMFDevSoundProxyBTBFEvent: sl@0: { sl@0: iAsyncQueueFinish->Cancel(); // if still active, means previous cycle did not Finish(). Cancel. sl@0: TRAP(err, DoBTBFCompleteL()); sl@0: if (err) sl@0: { sl@0: iAsyncQueueFinish->CallBack(); // async call to Finish() sl@0: iDevSoundObserver.PlayError(err); sl@0: } sl@0: } sl@0: break; sl@0: case EMMFDevSoundProxyBTBEEvent: sl@0: { sl@0: iAsyncQueueFinish->Cancel(); // if still active, means previous cycle did not Finish(). Cancel. sl@0: TRAP(err, DoBTBECompleteL()); sl@0: if (err) sl@0: { sl@0: iAsyncQueueFinish->CallBack(); // async call to Finish() sl@0: iDevSoundObserver.RecordError(err); sl@0: } sl@0: } sl@0: break; sl@0: case EMMFDevSoundProxyPEEvent: sl@0: { sl@0: if (iCurrentItem.iErrorCode == KErrDied || sl@0: iCurrentItem.iErrorCode == KErrNotReady) sl@0: { sl@0: DoPlayErrorComplete(); sl@0: // "this" pointer is no longer valid here as the associated sl@0: // instance of the DevSound has been deleted along with this sl@0: // CMsgQueueHandler object. So, we can only return here. sl@0: return; sl@0: } sl@0: else sl@0: { sl@0: DoPlayErrorComplete(); sl@0: break; sl@0: } sl@0: } sl@0: case EMMFDevSoundProxyREEvent: sl@0: { sl@0: DoRecordErrorComplete(); sl@0: break; sl@0: } sl@0: case EMMFDevSoundProxyTFEvent: sl@0: { sl@0: DoToneFinishedComplete(); sl@0: break; sl@0: } sl@0: case EMMFDevSoundProxySETCEvent: sl@0: { sl@0: DoSendEventToClientComplete(); sl@0: break; sl@0: } sl@0: case EMMFDevSoundCustomCommandCloseMuxDemuxPair: sl@0: { sl@0: TMMFEvent pckgevent = iCurrentItem.iEventPckg(); sl@0: TInt handle = pckgevent.iEventType.iUid; sl@0: iDevSoundCIObserver.CloseCustomInterface(handle); sl@0: break; sl@0: } sl@0: case EMMFDevSoundProxyPausedRecordCompleteEvent: sl@0: { sl@0: DoPausedRecordComplete(); sl@0: break; sl@0: } sl@0: default: sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::RunL - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::RunError sl@0: // Called by CActive object framework if RunL leaves. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: TInt CMsgQueueHandler::RunError(TInt aError) sl@0: { sl@0: SYMBIAN_DEBPRN1(_L("CMsgQueueHandler[0x%x]::RunError - Enter. Error [%d]"), aError); sl@0: TMMFEvent event; sl@0: event.iErrorCode = aError; sl@0: iDevSoundObserver.SendEventToClient(event); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::RunError - Exit")); sl@0: return KErrNone; sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoCancel sl@0: // Called when client cancels the wait for a completion of an outstanding sl@0: // request. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoCancel() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoCancel - Enter")); sl@0: iMsgQueue->CancelDataAvailable(); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoCancel - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoInitComplete sl@0: // Handles initialization completion event. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoInitComplete() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoInitComplete - Enter")); sl@0: iDevSoundObserver.InitializeComplete(iCurrentItem.iErrorCode); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoInitComplete - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoPlayErrorComplete sl@0: // Handles play completion or cancel event. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoPlayErrorComplete() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoPlayErrorComplete - Enter")); sl@0: iAsyncQueueFinish->CallBack(); // async call to Finish() sl@0: iDevSoundObserver.PlayError(iCurrentItem.iErrorCode); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoPlayErrorComplete - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoBTBFCompleteL sl@0: // Handles CMMFDevSound object's data request event to supply CMMFDevSound sl@0: // with the buffer that it needs to play. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoBTBFCompleteL() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoBTBFCompleteL - Enter")); sl@0: // Returns either chunk handle or NULL sl@0: // any error is assumed to be due to a pending PlayError(), so the error here is ignored - the PlayError() call will ensure the client remains lively sl@0: // the chunk has been closed by the server. No action should be taken. sl@0: TBool requestChunk = iDataBuffer==NULL; // if we have no buffer, tell server we need a chunk handle sl@0: TInt handle = iDevSoundProxy->BufferToBeFilledData(requestChunk, iSetPckg); sl@0: if(handle >= KErrNone) sl@0: { sl@0: if ( iSetPckg().iChunkOp == EOpen ) sl@0: { sl@0: AssignDataBufferToChunkL(handle); sl@0: } sl@0: else sl@0: { sl@0: UpdateDataBufferL(); sl@0: } sl@0: iDataBuffer->SetStatus(EAvailable); sl@0: sl@0: // Let the MMF fill the buffer with data sl@0: sl@0: iDevSoundObserver.BufferToBeFilled(iDataBuffer); sl@0: } sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoBTBFCompleteL - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoBTBECompleteL sl@0: // Handles CMMFDevSound object's data request event to supply CMMFDevSound sl@0: // with the buffer that it needs to record. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoBTBECompleteL() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoBTBECompleteL - Enter")); sl@0: // Returns either chunk handle or NULL sl@0: // any error is assumed to be due to a pending RecordError(), so the error here is ignored - the RecordError() call will ensure the client remains lively sl@0: // the chunk has been closed by the server. No action should be taken. sl@0: TInt handle = iDevSoundProxy->BufferToBeEmptiedData(iSetPckg); sl@0: if(handle >= KErrNone) sl@0: { sl@0: if ( iSetPckg().iChunkOp == EOpen ) sl@0: { sl@0: AssignDataBufferToChunkL(handle); sl@0: } sl@0: iDataBuffer->SetStatus(EFull); sl@0: iDataBuffer->Data().SetLength(iSetPckg().iRequestSize); sl@0: iDevSoundObserver.BufferToBeEmptied(iDataBuffer); sl@0: } sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoBTBECompleteL - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoRecordErrorComplete sl@0: // Handles record completion or cancel event. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoRecordErrorComplete() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoRecordErrorComplete - Enter")); sl@0: iAsyncQueueFinish->CallBack(); // async call to Finish() sl@0: iDevSoundObserver.RecordError(iCurrentItem.iErrorCode); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoRecordErrorComplete - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoToneFinishedComplete sl@0: // Handles tone play completion event. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoToneFinishedComplete() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoToneFinishedComplete - Enter")); sl@0: iDevSoundObserver.ToneFinished(iCurrentItem.iErrorCode); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoToneFinishedComplete - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoSendEventToClientComplete sl@0: // Sends DevSound server event completion notification to the client. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoSendEventToClientComplete() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoSendEventToClientComplete - Enter")); sl@0: iDevSoundObserver.SendEventToClient(iCurrentItem.iEventPckg()); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoSendEventToClientComplete - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::DoPausedRecordComplete sl@0: // Handles CMMFDevSound object's data request event to supply CMMFDevSound sl@0: // with the last buffer that it needs to record. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::DoPausedRecordComplete() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoPausedRecordComplete - Enter")); sl@0: ASSERT(iEmptyBuffer); sl@0: iEmptyBuffer->SetLastBuffer(ETrue); sl@0: iDevSoundObserver.BufferToBeEmptied(iEmptyBuffer); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoPausedRecordComplete - Exit")); sl@0: } sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CMsgQueueHandler::AssignDataBufferToChunkL sl@0: // Updates chunk handle. sl@0: // ---------------------------------------------------------------------------- sl@0: // sl@0: void CMsgQueueHandler::AssignDataBufferToChunkL(TInt aHandle) sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::AssignDataBufferToChunkL - Enter")); sl@0: if ( iChunk.Handle() ) sl@0: { sl@0: iChunk.Close(); sl@0: } sl@0: User::LeaveIfError(iChunk.SetReturnedHandle(aHandle)); sl@0: // Adjust ptr to map only requested size sl@0: // The existing clients should handle TPtr with length zero and max length sl@0: // iSetPckg().iBufferSize. sl@0: // When we make sure every client handles it, replace second parameter with sl@0: // zero. sl@0: //iChunkDataPtr.Set(iChunk.Base(), 0, iSetPckg().iBufferSize); sl@0: iChunkDataPtr.Set(iChunk.Base(), iSetPckg().iBufferSize, iSetPckg().iBufferSize); sl@0: if (!iDataBuffer) sl@0: { sl@0: iDataBuffer = CMMFPtrBuffer::NewL(); sl@0: } sl@0: UpdateDataBufferL(); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::AssignDataBufferToChunkL - Exit")); sl@0: } sl@0: sl@0: void CMsgQueueHandler::UpdateDataBufferL() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::UpdateDataBufferL - Enter")); sl@0: ASSERT(iDataBuffer); // to get here, we should have a data buffer sl@0: iDataBuffer->SetPtr(iChunkDataPtr); sl@0: iDataBuffer->SetRequestSizeL(iSetPckg().iRequestSize); sl@0: iDataBuffer->SetLastBuffer(EFalse); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::UpdateDataBufferL - Exit")); sl@0: } sl@0: sl@0: void CMsgQueueHandler::Finish() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::Finish - Enter")); sl@0: if (iDataBuffer) sl@0: { sl@0: delete iDataBuffer; sl@0: iDataBuffer = NULL; sl@0: } sl@0: if (iChunk.Handle()) sl@0: { sl@0: iChunk.Close(); sl@0: } sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::Finish - Exit")); sl@0: } sl@0: sl@0: // AsyncQueueStartCallback sl@0: sl@0: sl@0: TInt CMsgQueueHandler::AsyncQueueFinishCallback(TAny* aPtr) sl@0: { sl@0: CMsgQueueHandler* self = static_cast(aPtr); sl@0: self->DoAsyncQueueFinishCallback(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CMsgQueueHandler::DoAsyncQueueFinishCallback() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoAsyncQueueFinishCallback - Enter")); sl@0: Finish(); sl@0: SYMBIAN_DEBPRN0(_L("CMsgQueueHandler[0x%x]::DoAsyncQueueFinishCallback - Exit")); sl@0: } sl@0: sl@0: sl@0: // End of File