diff -r 000000000000 -r 71ca22bcf22a mmfenh/enhancedmediaclient/Client/src/Components/StreamControl/ClientStreamControl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmfenh/enhancedmediaclient/Client/src/Components/StreamControl/ClientStreamControl.cpp Tue Feb 02 01:08:46 2010 +0200 @@ -0,0 +1,906 @@ +/* +* Copyright (c) 2006 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: Implementation of the ClientStreamControl class. +* +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ClientStreamControl.h" +#include "EventNotifier.h" +#include "EventBase.h" +#include "ErrorCode.h" +#include "StateChangedEvent.h" +#include "CMCustomCommand.h" +#include "SourceBase.h" +#include "SinkBase.h" +#include "tracemacros.h" + +#define RETURN_IF_ERROR(x) if(x != KErrNone) return x + +#ifdef __WINDOWS_MEDIA +#ifndef RD_PD_FOR_AUDIO_CONTENT_VIA_HELIX_ENGINE +_LIT8(KWMAMimeType,"audio/x-ms-wma"); +#endif +#endif + +const TInt KMaxMimeLength = 256; + +using namespace multimedia; + +CStreamControl::CStreamControl() : + iStreamState(EStreamClosed), iStreamControlCustomCommands(iController) + { + // No impl yet + iError = KErrNone; + } + +CStreamControl::~CStreamControl() + { + EMC_TRACE1(_L("CStreamControl::~CStreamControl")); + // Don't have to send events to observers. + Close(); + delete iCMCustomCommand; + delete iEventNotifier; + delete iEventNotifierForEffects; + delete iControllerEventMonitor; + delete iFindAndOpenController; + // Signal associated effects that this instance is closed + TInt index(0); + CEffectControlBase* effectBase(NULL); + for (; index < iAssociatedEffects.Count(); index++) + { + effectBase = iAssociatedEffects[index]; + effectBase->StreamControlDeleted( *this); + } + iAssociatedEffects.Close(); + REComSession::FinalClose(); + } + +TInt CStreamControl::PostConstructor() + { + TInt status(KErrNone); + if (!iControllerEventMonitor) + { + TRAP(status, iControllerEventMonitor = CMMFControllerEventMonitor::NewL(*this, iController)); + } + RETURN_IF_ERROR(status); + + if (!iFindAndOpenController) + { + TRAP(status, iFindAndOpenController = CMMFFindAndOpenController::NewL(*this)); + } + RETURN_IF_ERROR(status); + + if (!iEventNotifier) + { + TRAP(status, iEventNotifier = CEventNotifier::NewL()); + } + if ( !iEventNotifierForEffects) + { + TRAP(status, iEventNotifierForEffects = CEventNotifier::NewL()); + } + + if (!iCMCustomCommand) + { + iCMCustomCommand = new CMCustomCommand(iController); + if ( !iCMCustomCommand) + status = KErrNoMemory; + } + return status; + } + +TInt CStreamControl::AddObserver(MControlObserver& aObserver) + { + return iEventNotifier->AddObserver(aObserver); + } + +TInt CStreamControl::RemoveObserver(MControlObserver& aObserver) + { + return iEventNotifier->RemoveObserver(aObserver); + } + +TUid CStreamControl::Type() + { + return KStreamControl; + } + +TControlType CStreamControl::ControlType() + { + return EStreamControl; + } + +TInt CStreamControl::AddSource(MSourceControl& aSource) + { + TInt status(KErrNotReady); + switch (iStreamState) + { + case EStreamClosed: + status = KErrAlreadyExists; + if ( !iSourceControl) + { + iSourceControl = &aSource; + status = KErrNone; + } + break; + default: + break; + }; + return status; + } + +TInt CStreamControl::RemoveSource(MSourceControl& aSource) + { + TInt status(KErrLocked); + switch (iStreamState) + { + case EStreamClosed: + status = KErrBadHandle; + if (iSourceControl == &aSource) + { + iSourceControl = NULL; + status = KErrNone; + } + break; + default: + break; + }; + return status; + } + +TInt CStreamControl::AddSink(MSinkControl& aSink) + { + TInt status(KErrNotReady); + switch (iStreamState) + { + case EStreamClosed: + status = KErrAlreadyExists; + if ( !iSinkControl) + { + iSinkControl = &aSink; + status = KErrNone; + } + break; + default: + break; + }; + return status; + } + +TInt CStreamControl::RemoveSink(MSinkControl& aSink) + { + TInt status(KErrLocked); + switch (iStreamState) + { + case EStreamClosed: + status = KErrBadHandle; + if (iSinkControl == &aSink) + { + iSinkControl = NULL; + status = KErrNone; + } + break; + default: + break; + }; + return status; + } + +TInt CStreamControl::RemoveEffect(MEffectControl& aEffect) + { + TInt status(KErrNotReady); + // Get the observer from effect + CEffectControlBase* effectBase = + dynamic_cast(&aEffect); + + // Remove the effect from the array + TInt index(KErrNotFound); + index = iAssociatedEffects.Find(effectBase); + if (index != KErrNotFound) + { + MControlObserver* observer; + status = effectBase->GetControlObserver(observer); + RETURN_IF_ERROR( status ); + + status = iEventNotifierForEffects->RemoveObserver( *observer); + RETURN_IF_ERROR( status ); + + iAssociatedEffects.Remove(index); + status = effectBase->RemovedFromStreamControl(*this); + RETURN_IF_ERROR( status ); + } + + return status; + } + +TInt CStreamControl::AddEffect(MEffectControl& aEffect) + { + TInt status(KErrNotReady); + + // Get the observer from effect + CEffectControlBase* effectBase = + dynamic_cast(&aEffect); + + MControlObserver* observer; + if (effectBase) + { + status = effectBase->GetControlObserver(observer); + } + RETURN_IF_ERROR( status ); + + if (iEventNotifierForEffects) + { + status = iEventNotifierForEffects->AddObserver( *observer); + } + RETURN_IF_ERROR( status ); + + // Add effect to array to notify Effects if user destroys Stream Control + // before removing all Effect Controls from this instance. + status = iAssociatedEffects.Append(effectBase); + RETURN_IF_ERROR( status ); + + status = effectBase->AddedToStreamControl( *this, *iCMCustomCommand, + aEffect); + + // If there was any error adding, undo operations and send error code to user. + if (status != KErrNone) + { + // Remove the effect from the array + TInt index(KErrNotFound); + index = iAssociatedEffects.Find(effectBase); + if (index != KErrNotFound) + { + iAssociatedEffects.Remove(index); + } + iEventNotifierForEffects->RemoveObserver( *observer); + } + + return status; + + } + +// Sets the current position microseconds +TInt CStreamControl::SetPosition(TInt64& aPos) + { + TInt status(KErrNone); + TTimeIntervalMicroSeconds timePos(aPos); + status = iController.SetPosition(timePos); + return status; + } + +TInt CStreamControl::SetPriority(TInt aPriority, TInt aPreference) + { + TInt status(KErrNone); + iPrioritySettings.iPriority = aPriority; + iPrioritySettings.iPref = TMdaPriorityPreference(aPreference); + + if (iStreamState != EStreamClosed) + { + status = iController.SetPrioritySettings(iPrioritySettings); + } + return status; + } + +TInt CStreamControl::GetDuration(TInt64& aDuration) + { + TInt status(KErrUnknown); + TTimeIntervalMicroSeconds duration; + status = iController.GetDuration(duration); + if (status == KErrNone) + { + aDuration = duration.Int64(); + } + return status; + } + +TInt CStreamControl::GetPosition(TInt64& aPos) + { + TInt status(KErrUnknown); + TTimeIntervalMicroSeconds posInTime; + status = iController.GetPosition(posInTime); + if (status == KErrNone) + { + aPos = posInTime.Int64(); + } + return status; + } + +TInt CStreamControl::GetSeekingSupport(TBool& aFlag) + { + TInt status(KErrNone); + status = iStreamControlCustomCommands.GetSeekingSupported(aFlag); + return status; + } + +TInt CStreamControl::GetRandomSeekingSupport(TBool& aFlag) + { + TInt status(KErrNone); + status = iStreamControlCustomCommands.GetRandomSeekingSupported(aFlag); + return status; + } + +MStreamControl::TStreamState CStreamControl::GetState() + { + return iState; + } + +TAny* CStreamControl::CustomInterface(TUid aCIUid) + { + TAny* retVal(NULL); + + // This function should only be called after the StreamControl + // is Initialized + if (aCIUid == KUidInterfaceMMFDRMControl) + { + RMMFDRMCustomCommands* drmCustCommand = new RMMFDRMCustomCommands(iController); + if (drmCustCommand && drmCustCommand->IsSupported()) + { + retVal = drmCustCommand; + } + else + { + delete drmCustCommand; + } + } + else + if (aCIUid == KUidSCControllerRef) + { + retVal = &iController; + EMC_TRACE2(_L("CStreamControl::CustomInterface [%x]"), retVal); + + } + else + if (aCIUid == KUidSCControllerUid) + { + retVal = &iControllerUid; + } + return retVal; + } + +TInt CStreamControl::Open() + { + EMC_TRACE1(_L("CStreamControl::Open")); + TInt status(KErrNotReady); + + switch (iStreamState) + { + case EStreamClosed: + if (iSourceControl) + { // Launch the controller + iStreamState = EStreamOpening; + status = LaunchController(); + } + break; + default: + break; + }; + return status; + } + +TInt CStreamControl::Prime() + { + EMC_TRACE1(_L("CStreamControl::Prime")); + TInt status(KErrNotReady); + switch (iStreamState) + { + case EStreamOpened: + iStreamState = EStreamPriming; + status = iController.Prime(); + iPrimeController = EFalse; + break; + case EStreamPriming: + status = KErrNone; + break; + default: + break; + }; + return status; + } + +TInt CStreamControl::Start() + { + EMC_TRACE1(_L("CStreamControl::Start")); + TInt status(KErrNotReady); + switch (iStreamState) + { + case EStreamOpened: + case EStreamPrimed: + case EStreamPaused: + case EStreamPriming: + case EStreamStartingPlaying://added for bug #ESLM-7X8A88 + iStreamState = EStreamStartingPlaying; + // If EOF prime controller before calling Play(). + if (iPrimeController) + { + status = iController.Prime(); + iPrimeController = EFalse; + } + else + { + // This is the case where Play a file, EOF reached and app calls + // Play() again. + status = iController.Play(); + } + break; + default: + break; + }; + return status; + } + +TInt CStreamControl::Pause() + { + EMC_TRACE1(_L("CStreamControl::Pause")); + TInt status(KErrNotReady); + switch (iStreamState) + { + case EStreamPlaying: + case EStreamBuffering: + case EStreamPrimed: + case EStreamPriming: + iStreamState = EStreamPausing; + status = iController.Pause(); + break; + case EStreamPaused: + status = KErrNone; + default: + break; + }; + return status; + } + + +TInt CStreamControl::Stop() + { + EMC_TRACE1(_L("CStreamControl::Stop")); + TInt status(KErrNotReady); + switch (iStreamState) + { + case EStreamOpened: + case EStreamPrimed: + case EStreamPlaying: + case EStreamPaused: + iStreamState = EStreamPriming; + status = iController.Stop(); + break; + default: + break; + }; + return status; + } + +TInt CStreamControl::Close() + { + EMC_TRACE1(_L("CStreamControl::Close")); + TInt status(KErrNotReady); + + // Disconnect All Effects. This makes sure that Effects + // delete their MessageHandlers before the Controller is Closed. + // This is done to Support AudioEffects in EMC. + // This is done because if Controller tries to delete MessageHandlers + // after deleting DevSound in the Destructor, there is a NULL pointer + // Exception. Untill that problem is fixed in DevSound this is the fix. + + TInt count = iAssociatedEffects.Count(); + for (TInt i = 0; i < count; i++) + { + iAssociatedEffects[i]->Disconnect(); + } + + if (iControllerEventMonitor) + { + iControllerEventMonitor->Cancel(); + } + + iController.Stop(); + iController.Close(); + + if (iFindAndOpenController) + { + iFindAndOpenController->Close(); + } + + // Signal the source that server side source is unloaded + if (iSourceControl) + { + CSourceBase* sourcebase = dynamic_cast(iSourceControl); + sourcebase->ServerSourceDeleted(); + } + + SetStreamState(EStreamClosed, KErrNone); + status = KErrNone; + return status; + } + +void CStreamControl::HandleEvent(const TMMFEvent& aEvent) + { + EMC_TRACE3(_L("CStreamControl::HandleEvent:Evt[%d]Err[%d]"), aEvent.iErrorCode, aEvent.iEventType); + + if (aEvent.iEventType == KStreamControlEventStateChangedStopped) + { + iPrimeController = ETrue; + SetStreamState(EStreamOpened, aEvent.iErrorCode); + // If playback is stopped due to EOF, set flag to prime controller when + // client calls Play() to play the same file/clip. + + } + else + if (aEvent.iEventType == KStreamControlEventStateChangedPrimed) + { + if (iStreamState == EStreamStartingPlaying) + { + iController.Play(); + } + else + { + SetStreamState(EStreamPrimed, KErrNone); + } + } + else + if (aEvent.iEventType == KStreamControlEventStateChangedPlaying) + { + SetStreamState(EStreamPlaying, KErrNone); + } + else + if (aEvent.iEventType + == KStreamControlEventStateChangedPaused) + { + SetStreamState(EStreamPaused, KErrNone); + } + else + if (aEvent.iEventType + == KStreamControlEventStateChangedAutoPaused) + { + SetStreamState(EStreamBuffering, KErrNone); + } + else + if (aEvent.iEventType + == KStreamControlEventDurationChanged) + { + SendEventToClient( + MStreamControlObserver::KDurationChangedEvent, + NULL); + } + else + if (aEvent.iEventType + == KStreamControlEventSeekingSupportChanged) + { + SendEventToClient( + MStreamControlObserver::KSeekingSupportChangedEvent, + NULL); + } + else + if (aEvent.iEventType + == KStreamControlEventRandomSeekingSupportChanged) + { + SendEventToClient( + MStreamControlObserver::KRandomSeekingSupportChangedEvent, + NULL); + } + else + if (aEvent.iEventType + == KMMFEventCategoryPlaybackComplete) + { // KMMFEventCategoryPlaybackComplete will no longer be needed once + // controller start sending state changed events. + SetStreamState(EStreamOpened, KErrEof); + iPrimeController = ETrue; + } + } + +void CStreamControl::MfaocComplete(TInt& aError, + RMMFController* /*aController*/, TUid aControllerUid, + TMMFMessageDestination* aSourceHandle, TMMFMessageDestination* /*aSinkHandle*/) + { + EMC_TRACE3(_L("CStreamControl::MfaocComplete:Err[%d]aSourceHandle[0x%x]"), aError, aSourceHandle); + if (aError == KErrNone) + { + iControllerLoaded = ETrue; + // Configure the controller to send state change events. + TInt error = iStreamControlCustomCommands.EnableEvents(ETrue); + if (error != KErrNone) + { + // We should error out and not let apps to continue. This player + // only works with controllers that send state events. + + // The same sequence occurs in Close() also. May be move this a + // seperate function and call function here... + + // Signal the source that server side source is unloaded + CSourceBase* sourcebase = + dynamic_cast(iSourceControl); + sourcebase->ServerSourceDeleted(); + + if (iControllerEventMonitor) + { + iControllerEventMonitor->Cancel(); + } + + iController.Stop(); + iController.Close(); + + if (iFindAndOpenController) + { + iFindAndOpenController->Close(); + } + // If the stream is already in CLOSED state + // send an error event. + if (iState == CLOSED) + { + /*EError*/ + EMC_TRACE1(_L("CStreamControl::MfaocComplete:ERROR[KErrNotSupported]")); + } + else + { + SetStreamState(EStreamClosed, KErrNotSupported); + } + } + else + { + + if (!iControllerEventMonitor->IsActive()) + { + iControllerEventMonitor->Start(); + } + + // Save the uid of controller loaded. + iControllerUid = aControllerUid; + // Signal the source that server side source is loaded + CSourceBase* sourcebase = + dynamic_cast(iSourceControl); + sourcebase->ServerSourceCreated( *iCMCustomCommand, + *aSourceHandle); + + if (iStreamState == EStreamOpening) + { + iPrimeController = ETrue; + SetStreamState(EStreamOpened, KErrNone); + //FIX ME we need to do this even when the controller is closed + CErrorCode* eventforEffects = new CErrorCode( KErrNone ); + SendEventToEffectControls( + CEffectControlBase::ECIBuilderCreated, + eventforEffects); + } + } + } + else + { + SetStreamState(EStreamClosed, aError); + } + } + +void CStreamControl::ConfigureControllerLoader(TUid aMediaType, + CMMFFindAndOpenController::TControllerMode aMode) + { + iFindAndOpenController->Configure(aMediaType, iPrioritySettings); + iFindAndOpenController->ConfigureController(iController, + *iControllerEventMonitor, aMode); + } + +TInt CStreamControl::LaunchController() + { + TInt status(KErrNone); + // KUidMediaTypeAudio need to be part of source + ConfigureControllerLoader(KUidMediaTypeAudio, + CMMFFindAndOpenController::EPlayback); + // if Streaming case + + if (!iSourceControl || !iSinkControl) + return KErrNotReady; + + TUid sourceUID = (dynamic_cast(iSourceControl))->GetSourceUid(); + TUid sinkUID = (dynamic_cast(iSinkControl))->GetSinkUid(); + + if (iSourceControl->Type() == KDataBufferSourceControl) + { + MDataBufferSource* streamingSource = + static_cast(iSourceControl); + iFindAndOpenController->ConfigureSourceSink( + CMMFFindAndOpenController::TSourceSink( /*TUid::Uid(0x10207AF3)*/sourceUID), + CMMFFindAndOpenController::TSourceSink( /*KUidMmfAudioOutput*/sinkUID) ); + TBuf8 mimeType; + status = streamingSource->GetMimeType(mimeType); + if (status == KErrNone) + { + + // This Flag is defined so that if the Helix Controller Supports + // the playback of Local Media for WMA, then the HTTP Streaming still + // goes through the Old WMA Controller( AdvancedAudioController) + // We are launching the Old WMA Controller using the UID. + +#ifdef __WINDOWS_MEDIA +#ifndef RD_PD_FOR_AUDIO_CONTENT_VIA_HELIX_ENGINE + if(!mimeType.Compare(KWMAMimeType())) + { + iFindAndOpenController->OpenByControllerUid(TUid::Uid(0x10207A9B),KNullUid); + } + else +#endif +#endif + { + iFindAndOpenController->OpenByMimeType(mimeType); + } + } + } + else + if (iSourceControl->Type() == KProgDLSourceControl) + { + MProgDLSource* progDLSource = + static_cast(iSourceControl); + HBufC* fileName = HBufC::NewLC(KMaxPath); + TPtr fileNamePtr = fileName->Des(); + + TInt err = progDLSource->FileName(fileNamePtr); + + HBufC8* mimeType = HBufC8::NewLC(KMaxMimeLength); + TPtr8 mimeTypePtr = mimeType->Des(); + + TInt status = iSourceControl->GetMimeType(mimeTypePtr); + + iFindAndOpenController->ConfigureSourceSink( + TMMFileSource(fileNamePtr, + ContentAccess::KDefaultContentObject, + ContentAccess::EPlay), + CMMFFindAndOpenController::TSourceSink(/*KUidMmfAudioOutput*/sinkUID/*,fileHandle*/)); + + TMMFileSource source(fileNamePtr, + ContentAccess::KDefaultContentObject, + ContentAccess::EPlay); + + // This Flag is defined so that if the Helix Controller Supports + // the playback of Local Media for WMA, then the Progressive Download + // for WMA still goes through the Old WMA Controller( AdvancedAudioController) + // We are launching the Old WMA Controller using the UID. + +#ifdef __WINDOWS_MEDIA +#ifndef RD_PD_FOR_AUDIO_CONTENT_VIA_HELIX_ENGINE + if(!mimeTypePtr.Compare(KWMAMimeType())) + { + iFindAndOpenController->OpenByControllerUid(TUid::Uid(0x10207A9B),KNullUid); + } + else +#endif +#endif + { + iFindAndOpenController->OpenByFileSource(source); + } + + CleanupStack::PopAndDestroy(mimeType); // mimeType + CleanupStack::PopAndDestroy(fileName); // fileName + //fileHandle.Close(); + } + + if (iSourceControl->Type() == KFileSourceControl) + { + MFileSource* fileSource = static_cast(iSourceControl); + + HBufC* fileName = HBufC::NewLC(KMaxPath); + TPtr fileNamePtr = fileName->Des(); + + TInt err = fileSource->GetFileName(fileNamePtr); + + HBufC8* fileName1 = HBufC8::NewLC(KMaxPath); + TPtr8 fileNamePtr1 = fileName1->Des(); + fileNamePtr1.Copy(fileNamePtr); + + HBufC8* mimeType = HBufC8::NewLC(KMaxMimeLength); + TPtr8 mimeTypePtr = mimeType->Des(); + + TInt status = iSourceControl->GetMimeType(mimeTypePtr); + + iFindAndOpenController->ConfigureSourceSink( + CMMFFindAndOpenController::TSourceSink(sourceUID, + fileNamePtr1), + CMMFFindAndOpenController::TSourceSink(sinkUID)); + + TMMFileSource source(fileNamePtr, + ContentAccess::KDefaultContentObject, ContentAccess::EPlay); + iFindAndOpenController->OpenByFileSource(source); + + CleanupStack::PopAndDestroy(mimeType); // mimeType + CleanupStack::PopAndDestroy(fileName1); // fileName + CleanupStack::PopAndDestroy(fileName); // fileName + } + + if (iSourceControl->Type() == KDescriptorSourceControl) + { + MDescriptorSource* descriptorSource = + static_cast(iSourceControl); + iFindAndOpenController->ConfigureSourceSink( + CMMFFindAndOpenController::TSourceSink( /*TUid::Uid(0x10207AF3)*/sourceUID), + CMMFFindAndOpenController::TSourceSink( /*KUidMmfAudioOutput*/sinkUID) ); + TBuf8 mimeType; + status = descriptorSource->GetMimeType(mimeType); + if (status == KErrNone) + { + // This Flag is defined so that if the Helix Controller Supports + // the playback of Local Media for WMA, then the HTTP Streaming still + // goes through the Old WMA Controller( AdvancedAudioController) + // We are launching the Old WMA Controller using the UID. + + iFindAndOpenController->OpenByMimeType(mimeType); + } + } + return status; + } + +void CStreamControl::SetStreamState(TStreamControlState aState, TInt aReason) + { + EMC_TRACE4(_L("CStreamControl::SetStreamState:aState[%d]aReason[%d]iState[%d]"), \ + aState, aReason, iState); + TStreamState prevState = iState; + TInt prevError = iError; + iError = aReason; + switch (aState) + { + case EStreamClosed: + iStreamState = EStreamClosed; + iState = CLOSED; + break; + case EStreamOpened: + iStreamState = EStreamOpened; + iState = INITIALIZED; + break; + case EStreamPrimed: + iStreamState = EStreamPrimed; + iState = PRIMED; + break; + case EStreamPlaying: + iStreamState = EStreamPlaying; + iState = EXECUTING; + break; + case EStreamPaused: + iStreamState = EStreamPaused; + iState = PAUSED; + break; + case EStreamBuffering: + iStreamState = EStreamBuffering; + iState = BUFFERING; + break; + default: + break; + }; + // If there is a change in state notify client + if (prevState != iState || iError != prevError) + { + CStateChangedEvent* event(NULL); + //EMC_TRACE3(_L("CStreamControl::SetStreamState Before iState [%d] prevState [%d]"), + // iState,prevState); + //EMC_TRACE3(_L("CStreamControl::SetStreamState Before iError [%d] prevError [%d]"), iError,prevError); + event = new CStateChangedEvent( iState, aReason ); + //EMC_TRACE3(_L("CStreamControl::SetStreamState After iState [%d] iReason [%d]"), event->GetState() ,event->GetErrorCode()); + SendEventToClient(MStreamControlObserver::KStateChangedEvent, event); + } + } + +void CStreamControl::SendEventToClient(TUint aEvent, CEventBase* aEventObject) + { + iEventNotifier->Event(this, aEvent, aEventObject); + } + +void CStreamControl::SendEventToEffectControls(TUint aEvent, + CEventBase* aEventObject) + { + iEventNotifierForEffects->Event( this, aEvent, aEventObject); + } +// End of file