diff -r f9bb0fca356a -r 0fd27995241b javauis/mmapi_qt/baseline/src/cmmamidiplayer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/mmapi_qt/baseline/src/cmmamidiplayer.cpp Tue May 11 16:07:20 2010 +0300 @@ -0,0 +1,590 @@ +/* +* Copyright (c) 2002-2007 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: This class is used for MIDI. +* +*/ + + +// INCLUDE FILES +#include +#include +#include +#include + +#include "cmmamidiplayer.h" +#include "mmmadisplay.h" + +const TInt KErrorMessageSize = 32; +_LIT(KErrDefaultError, "Symbian OS Error: %d"); +const TInt KMidiDefaultBank = 0x3c80; +const TInt KMidiDrumBank = 0x3c7c; +const TInt KMidiDrumChannel = 9; +const TInt KMidiChannels = 16; +const TInt KMidiDefaultInstrument = 1; + +CMMAMIDIPlayer* CMMAMIDIPlayer::NewLC(const TDesC& aContentType, + TFileName aFileName) +{ + CMMAMIDIPlayer* self = new(ELeave) CMMAMIDIPlayer(aFileName); + CleanupStack::PushL(self); + self->ConstructL(aContentType); + return self; +} + +CMMAMIDIPlayer::~CMMAMIDIPlayer() +{ + CloseClientUtility(); + // new function added to CMMAPlayer delete the controls before the destruction of iMidi. + DeleteControls(); + delete iMidi; + delete iActiveSchedulerWait; + iObservers.Close(); + + LOG( EJavaMMAPI, EInfo, "MMA::CMMAMIDIPlayer::~CMMAMIDIPlayer"); +} + +void CMMAMIDIPlayer::ConstructL(const TDesC& aContentType) +{ + LOG( EJavaMMAPI, EInfo, "CMMAMIDIPlayer::ConstructL"); + iContentType = aContentType.AllocL(); + iActiveSchedulerWait = new(ELeave)CActiveSchedulerWait; + iMidi = CMidiClientUtility::NewL(*this, KAudioPriorityRecording, + KMMAMIDIPriorityPreference, ETrue); + + CMMAPlayer::ConstructL(); +} + +CMMAMIDIPlayer::CMMAMIDIPlayer(TFileName aFileName): + iFileName(aFileName), + iMediaTime(KTimeUnknown), iStartedEventTime(0) +{ +} + +EXPORT_C CMidiClientUtility* CMMAMIDIPlayer::MidiClient() const +{ + return iMidi; +} + + +void CMMAMIDIPlayer::RealizeL() +{ + LOG( EJavaMMAPI, EInfo, "CMMAMIDIPlayer::RealizeL"); + CMMAPlayer::RealizeL(); +} + +void CMMAMIDIPlayer::PrefetchL() +{ + LOG1( EJavaMMAPI, EInfo, "CMMAMIDIPlayer::PrefetchL stream count %d", iSourceStreams.Count()); + if (iFileName != KNullDesC) + { + iMidi->OpenFile(iFileName); + } + else if (iSourceStreams.Count() == 0) + { + // We have no data, but need to initialize the player + // Preparing all channels + for (TInt i = 0; i < KMidiChannels; i++) + { + iMidi->SetInstrumentL(i, KMidiDefaultBank, + KMidiDefaultInstrument); + } + + // Setting drums to channel 10 + iMidi->SetInstrumentL(KMidiDrumChannel, KMidiDrumBank, + KMidiDefaultInstrument); + + // Start it immediately in order to get MIDIControl work without + // calling the start. This is how reference implementation works. + iMidi->Play(); + } + else + { + // Created with content, audio player will initialize controller + // and data source. + iSourceStreams[ 0 ]->ReadAllL(); + } +} + +// +// This method is called when CMMASourceStreamReader finished reading +// initiated in PrefetchL +// +void CMMAMIDIPlayer::ReadCompletedL(TInt aStatus, const TDesC8& aData) +{ + if (aStatus < KErrNone) + { + PostActionCompleted(aStatus); + } + else + { + // we're not finished yet + iMidi->OpenDes(aData); //wait for MMidiClientUtilityObserver::MmcuoStateChanged + } +} + +void CMMAMIDIPlayer::DeallocateL() +{ + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer: DeallocateL +"); + if (iState == EPrefetched) + { + CloseClientUtility(); + ResetSourceStreams(); + ChangeState(ERealized); + } + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer: DeallocateL -"); +} + +void CMMAMIDIPlayer::StartL() +{ + iMediaTime = KTimeUnknown; + + // Player is already started if this player is constructed with + // device://midi locator. + TBool isDeviceMidi = (iSourceStreams.Count() == 0 && + iFileName == KNullDesC); + if (!isDeviceMidi) + { + iMidi->Play(); + } + + // inform java side + PostLongEvent(CMMAPlayerEvent::EStarted, iStartedEventTime); + ChangeState(EStarted); + + // To achieve similar functionality as reference implementation, + // END_OF_MEDIA must be sent right after Start on device://midi. + if (isDeviceMidi) + { + PostLongEvent(CMMAPlayerEvent::EEndOfMedia, iStartedEventTime); + ChangeState(EPrefetched); + } + PostActionCompletedStart(); + //PostActionCompleted(KErrNone); // java start return +} + +void CMMAMIDIPlayer::StopL(TBool aPostEvent) +{ + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer::StopL"); + if (iState == EStarted) + { + TInt64 time; + GetMediaTime(&time); + iStartedEventTime = time; + + // do the stop only if we are playing some content + if ((iSourceStreams.Count() > 0) || + (iFileName != KNullDesC)) + { + // should actually pause!!! + iMidi->Stop(TTimeIntervalMicroSeconds(0)); + } + + if (aPostEvent) + { + PostLongEvent(CMMAPlayerEvent::EStopped, time); + } + // go back to prefetched state + ChangeState(EPrefetched); + } +} + +void CMMAMIDIPlayer::GetDuration(TInt64* aDuration) +{ + // Special case for device://midi + if ((iSourceStreams.Count() == 0) && + (iFileName == KNullDesC)) + { + iDuration = KErrNone; + } + else if (iDuration == KTimeUnknown) + { + TRAPD(err, iDuration = iMidi->DurationMicroSecondsL().Int64()); + if (err != KErrNone) + { + // Duration was not available. + iDuration = KTimeUnknown; + } + } + + *aDuration = iDuration; +} + +void CMMAMIDIPlayer::SetMediaTimeL(TInt64* aTime) +{ + TTimeIntervalMicroSeconds position(*aTime); + iMidi->SetPositionMicroSecondsL(position); + + // Reset cached media time, because actual set position may be + // something else than aTime. + iMediaTime = KTimeUnknown; + + // Inform about the position change to the StateListeners + ChangeState(iState); + + // Get the actual media time + GetMediaTime(aTime); + + iStartedEventTime = iMediaTime; +} + +void CMMAMIDIPlayer::GetMediaTime(TInt64* aMediaTime) +{ + // Special case for device://midi + if ((iSourceStreams.Count() == 0) && + (iFileName == KNullDesC)) + { + iMediaTime = KErrNone; + } + else if (iMediaTime == KTimeUnknown || iState == EStarted) + { + TTimeIntervalMicroSeconds position(0); + TRAPD(error, position = iMidi->PositionMicroSecondsL()); + + if (error == KErrNone) + { + TInt64 newTime = position.Int64(); + + // Sanity check for media time going backwards or beyond the + // duration. + // Some native controls may return zero media time for + // a few moments just before playback will complete. + if (newTime < iMediaTime || + (iDuration > 0 && newTime > iDuration)) + { + GetDuration(&iMediaTime); + } + else + { + // set return value + iMediaTime = newTime; + } + } + else + { + // media time cannot be get + iMediaTime = KTimeUnknown; + } + } + *aMediaTime = iMediaTime; +} + +void CMMAMIDIPlayer::ReInitializeMidiEngineL(const TDesC8* aMidiSequence) +{ + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMIDIPlayer: ReInitializeMidiEngineL: + "); + + CloseClientUtility(); + + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer: ReInitializeMidiEngineL: Opening descriptor"); + + iMidi->OpenDes(*aMidiSequence); + // Wait until asynchronous OpenDes call has completed + if (!iActiveSchedulerWait->IsStarted()) + { + iActiveSchedulerWait->Start(); + } + ChangeState(EPrefetched); + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMIDIPlayer: ReInitializeMidiEngineL: - "); +} + +void CMMAMIDIPlayer::addObserverL(MMidiClientUtilityObserver* aObserver) +{ + iObservers.AppendL(aObserver); +} + +void CMMAMIDIPlayer::CloseL() +{ + CMMAPlayer::CloseL(); + CloseClientUtility(); +} + +const TDesC& CMMAMIDIPlayer::Type() +{ + return KMMAMIDIPlayer; +} + +void CMMAMIDIPlayer::PlayCompleteL(TInt aError) +{ + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer: PlayCompleteL +"); + ELOG1( EJavaMMAPI, "MMA: CMMAMidiPlayer: PlayCompleteL: Error=%d", aError); + TInt64 duration; + GetDuration(&duration); + iMediaTime = duration; + iStartedEventTime = 0; + + iMidi->Stop(TTimeIntervalMicroSeconds(0)); + + // go back to prefetched state + ChangeState(EPrefetched); // ready to play again + + // Send 'Stopped' only when stop() is called. + PostLongEvent(CMMAPlayerEvent::EEndOfMedia, duration); + + if (aError == KErrNone) + { + iRepeatCount++; + + if (iRepeatForever || iRepeatCount < iRepeatNumberOfTimes) + { + StartL(); + } + else + { + iRepeatCount = 0; + } + } + else + { + // error has occured, setting correct number of + // repeats for next start + SetLoopCount(iRepeatNumberOfTimes); + } + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer: PlayCompleteL -"); +} + +void CMMAMIDIPlayer::MmcuoStateChanged(TMidiState aOldState, + TMidiState aNewState, + const TTimeIntervalMicroSeconds& aTime, + TInt aError) +{ + TInt err = aError; + + ELOG3( EJavaMMAPI, "MMA: CMMAMIDIPlayer: MmcuoStateChanged: Old=%d, New=%d, Error=%d", + aOldState, + aNewState, + err); + // Closing the utility or reinitialising +#ifdef RD_JAVA_TMIDISTATECHANGE + if (iActiveSchedulerWait->IsStarted() && + ((aNewState == EMidiStateClosedDisengaged) || + (aNewState == EMidiStateOpenDisengaged) || + (aNewState == EMidiStateClosedEngaged))) +#else + if (iActiveSchedulerWait->IsStarted() && + ((aNewState == EClosedDisengaged) || + (aNewState == EOpenDisengaged) || + (aNewState == EClosedEngaged))) +#endif + { + iActiveSchedulerWait->AsyncStop(); + } + // changing from realized to prefetched state +#ifdef RD_JAVA_TMIDISTATECHANGE + else if ((iState == ERealized) && + (aOldState == EMidiStateClosedDisengaged) && + ((aNewState == EMidiStateOpenDisengaged) || + (aNewState == EMidiStateClosedEngaged) || + (aNewState == EMidiStateClosedDisengaged))) +#else + else if ((iState == ERealized) && + (aOldState == EClosed) && + ((aNewState == EOpen) || (aNewState == EClosedEngaged) || + (aNewState == EClosed))) // EClosed is EClosedDisengaged +#endif + { + if (aError == KErrNone) + { + // prefetch succeed + ChangeState(EPrefetched); + } + // else state remains realized + + // inform java + PostActionCompleted(aError); + err = KErrNone; // don't report the error again + } +#ifdef RD_JAVA_TMIDISTATECHANGE + else if ((aOldState == EMidiStateOpenPlaying) && + (aNewState == EMidiStateOpenEngaged) && + (iState == EStarted)) +#else + else if ((aOldState == EPlaying) && + (aNewState == EOpenEngaged) && + (iState == EStarted)) +#endif + { + // If iState is not EStarted PlayCompleteL may not be called because + // player may be already stopped. + + // playing completed + TRAPD(playErr, PlayCompleteL(aError)); + if (playErr != KErrNone) + { + err = playErr; + } + } + + if (err != KErrNone) + { + TBuf errorMessage; + errorMessage.Format(KErrDefaultError, err); + PostStringEvent(CMMAPlayerEvent::EError, errorMessage); + if (iActiveSchedulerWait->IsStarted()) + { + iActiveSchedulerWait->AsyncStop(); + } + } + + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoStateChanged(aOldState, aNewState, aTime, aError); + } + + LOG1( EJavaMMAPI, EInfo, "MMA: CMMAMIDIPlayer: MmcuoStateChanged: midi state %d", + iMidi->State()); +} + +void CMMAMIDIPlayer::MmcuoTempoChanged(TInt aMicroBeatsPerMinute) +{ + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoTempoChanged(aMicroBeatsPerMinute); + } +} + +void CMMAMIDIPlayer::MmcuoVolumeChanged(TInt aChannel,TReal32 aVolumeInDecibels) +{ + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoVolumeChanged(aChannel, aVolumeInDecibels); + } +} + +void CMMAMIDIPlayer::MmcuoMuteChanged(TInt aChannel,TBool aMuted) +{ + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoMuteChanged(aChannel, aMuted); + } +} + +void CMMAMIDIPlayer::MmcuoSyncUpdate(const TTimeIntervalMicroSeconds& aMicroSeconds,TInt64 aMicroBeats) +{ + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoSyncUpdate(aMicroSeconds, aMicroBeats); + } +} + +void CMMAMIDIPlayer::MmcuoMetaDataEntryFound(const TInt aMetaDataEntryId,const TTimeIntervalMicroSeconds& aPosition) +{ + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoMetaDataEntryFound(aMetaDataEntryId, aPosition); + } +} + +void CMMAMIDIPlayer::MmcuoMipMessageReceived(const RArray& aMessage) +{ + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoMipMessageReceived(aMessage); + } +} + +void CMMAMIDIPlayer::MmcuoPolyphonyChanged(TInt aNewPolyphony) +{ + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoPolyphonyChanged(aNewPolyphony); + } +} + +void CMMAMIDIPlayer::MmcuoInstrumentChanged(TInt aChannel,TInt aBankId,TInt aInstrumentId) +{ + // notify observers + TInt count = iObservers.Count(); + for (TInt i = 0; i < count; i++) + { + iObservers[ i ]->MmcuoInstrumentChanged(aChannel, aBankId, aInstrumentId); + } +} + +void CMMAMIDIPlayer::CloseClientUtility() +{ + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer: CloseClientUtility +"); + if (iMidi && + iActiveSchedulerWait && +#ifdef RD_JAVA_TMIDISTATECHANGE + (iMidi->State() != EMidiStateClosedDisengaged)) +#else + (iMidi->State() != EClosed)) +#endif + { + // Have to stop midi before closing, + // this case is for device://midi +#ifdef RD_JAVA_TMIDISTATECHANGE + if (iMidi->State() == EMidiStateClosedEngaged) +#else + if (iMidi->State() == EClosedEngaged) +#endif + { + iMidi->Stop(TTimeIntervalMicroSeconds(0)); + if (!iActiveSchedulerWait->IsStarted()) + { + iActiveSchedulerWait->Start(); + } + } + else + { + // Calling Close and Stop or Stop and Close should + // always lead to EClosed state. + + // From EOpenEngaged or EOpenPlaying to EClosedEngaged + // or from EOpenDisengaged to EClosedDisengaged + iMidi->Close(); + if (!iActiveSchedulerWait->IsStarted()) + { + iActiveSchedulerWait->Start(); + } + + LOG1( EJavaMMAPI, EInfo, "State after Close: %d", iMidi->State()); + + // If not in EClosedDisengaged yet +#ifdef RD_JAVA_TMIDISTATECHANGE + if (iMidi->State() != EMidiStateClosedDisengaged) +#else + if (iMidi->State() != EClosed) +#endif + { + // From EClosedEngaged to EClosedDisengaged + iMidi->Stop(TTimeIntervalMicroSeconds(0)); + if (!iActiveSchedulerWait->IsStarted()) + { + iActiveSchedulerWait->Start(); + } + LOG1( EJavaMMAPI, EInfo, "State after Stop: %d", iMidi->State()); + } + } + LOG1( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer: CloseClientUtility: State after close: %d", iMidi->State()); + } + LOG( EJavaMMAPI, EInfo, "MMA: CMMAMidiPlayer: CloseClientUtility -"); +} + +// END OF FILE