/*
* 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 a RecordControl.
*
*/
// INCLUDE FILES
#include <logger.h>
#include "cmmarecordcontrol.h"
#include "cmmaplayer.h"
_LIT(KControlName, "RecordControl");
CMMARecordControl::CMMARecordControl(CMMAPlayer* aPlayer):
iState(ERecordUninitialized),
iPlayer(aPlayer),
iStartTime(0)
{
}
CMMARecordControl::~CMMARecordControl()
{
iRecordPauseTimer.Cancel();
iRecordPauseTimer.Close();
if (iPlayer)
{
iPlayer->RemoveStateListener(this);
}
delete iOutputStream;
iFile.Close();
iFs.Delete(iFilename);
iFs.Close();
}
void CMMARecordControl::WaitForPauseL(const TInt64& aMediaTime)
{
// reusing time variable
TInt64 time = iStartTime - aMediaTime + KMinRecordPauseInterval;
iStartTime = 0;
LOG1(EJavaMMAPI, EInfo, "CMMARecordControl::WaitForPauseL wait time = %d", (TInt)time);
// if time > 0, time between record and pause is smaller than
// KMinRecordPauseInterval and we have to wait.
if (time > 0)
{
TRequestStatus status;
iRecordPauseTimer.Cancel();
iRecordPauseTimer.After(status, I64INT(time));
User::WaitForRequest(status);
// Status ignored because recording must be stopped.
}
}
void CMMARecordControl::ConstructL()
{
User::LeaveIfError(iRecordPauseTimer.CreateLocal());
User::LeaveIfError(iFs.Connect());
// create temporary file for recording
User::LeaveIfError(iFile.Temp(iFs,
KMMARecordTempDirectory,
iFilename,
EFileRead | EFileWrite | EFileShareAny));
iPlayer->AddStateListenerL(this);
}
void CMMARecordControl::StartRecordL()
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::StartRecordL+");
// Initialize needs to be done only once after setRecordLocation or
// setRecordStream and before commit or reset. Although startRecord can be
// called several times in the process, the initialization must happen
// only in the first call to startRecord
if (iState == ERecordUninitialized)
{
InitializeL();
}
iState = ERecordStandBy;
// calling next state if player is already started
NextStateL(iPlayer->State());
iPlayer->GetMediaTime(&iStartTime);
iPlayer->PostLongEvent(CMMAPlayerEvent::ERecordStarted, iStartTime);
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::StartRecordL-");
}
void CMMARecordControl::StopRecordL()
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::StopRecordL+");
if (iState == ERecordRecording)
{
NextStateL(iPlayer->State());
}
iState = ERecordInitialized;
// ask mediatime again for more accurate value
TInt64 time;
iPlayer->GetMediaTime(&time);
iPlayer->PostLongEvent(CMMAPlayerEvent::ERecordStopped, time);
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::StopRecordL-");
}
void CMMARecordControl::CommitL()
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::CommitL+");
// reset the recorder if already initialized
if (iState > ERecordUninitialized)
{
DoResetL();
}
else
{
// not even initialized yet, just inform java
iOutputStream->WriteL(KNullDesC8);
return;
}
iState = ERecordUninitialized;
// Create buffer for file context
TInt fileSize;
User::LeaveIfError(iFile.Size(fileSize));
LOG1(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::CommitL size in bytes = %d", fileSize);
HBufC8* data = HBufC8::NewLC(fileSize);
// Read file context
TPtr8 dataPtr = data->Des();
TInt pos(0);
User::LeaveIfError(iFile.Seek(ESeekStart, pos));
User::LeaveIfError(iFile.Read(dataPtr));
User::LeaveIfError(iFile.SetSize(0));
User::LeaveIfError(iFile.Flush());
// Write whole video data to stream
iOutputStream->WriteL(dataPtr);
CleanupStack::PopAndDestroy(data);
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::CommitL-");
}
void CMMARecordControl::ResetL()
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::ResetL+");
// reset the recorder if already initialized
if (iState > ERecordUninitialized)
{
DoResetL();
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::DoResetL done");
iState = ERecordUninitialized;
// Empty file that it can be reused
User::LeaveIfError(iFile.SetSize(0));
User::LeaveIfError(iFile.Flush());
}
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::ResetL-");
}
void CMMARecordControl::SetRecordStream(CMMAOutputStream* aStream)
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::SetRecordStream");
__ASSERT_DEBUG(aStream, User::Panic(
_L("CMMAVideoRecordControl:: Stream is NULL."),
KErrArgument));
delete iOutputStream;
iOutputStream = aStream;
}
HBufC* CMMARecordControl::GetContentTypeL()
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::GetContentTypeL");
return iPlayer->ContentType();
}
const TDesC& CMMARecordControl::ClassName() const
{
return KControlName;
}
void CMMARecordControl::StateChanged(TInt aState)
{
TRAPD(err, NextStateL(aState));
if (err)
{
Error(err);
}
}
void CMMARecordControl::Error(TInt aErrorCode)
{
ELOG1(EJavaMMAPI, "MMA:CMMARecordControl::Error %d", aErrorCode);
TBuf<KRecordErrorMessageSize> errorMessage;
errorMessage.Format(KMMARecordErrorMsg, aErrorCode);
iPlayer->PostStringEvent(CMMAPlayerEvent::ERecordError,
errorMessage);
}
void CMMARecordControl::HandleRecordSizeLimit()
{
// commit the stream
iOutputStream->Commit();
TInt64 time;
iPlayer->GetMediaTime(&time);
iPlayer->PostLongEvent(CMMAPlayerEvent::ERecordStopped, time);
}
void CMMARecordControl::NextStateL(TInt aPlayerState)
{
LOG1(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::NextStateL Player state = %d", aPlayerState);
LOG1(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::NextStateL internal state = %d", iState);
switch (iState)
{
case ERecordUninitialized:
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::NextStateL: case ERecordUninitialized");
// This is the initial state.
// To getinto this state, commit or reset must be called
// To get out of this state startRecord must be called
break;
}
case ERecordInitialized:
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::NextStateL: case ERecordInitialized");
// To get into this state stopRecord must be called.
// To get out of this state startRecord, commit or reset must be
// called
break;
}
case ERecordStandBy:
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::NextStateL: case ERecordStandBy");
// To get into this state startRecord must be called.
// To get out of this state stopRecord, commit or reset must be
// called, or state of the Player must change to STARTED
// start the actual recording if player is started
if (aPlayerState == CMMAPlayer::EStarted)
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::NextStateL: ERecordStandBy -> ERecordRecording");
DoStartRecordL();
iState = ERecordRecording;
}
break;
}
case ERecordRecording:
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::NextStateL: case ERecordRecording");
// To get into this state startRecord must have been called and
// the Player must be in STARTED state.
// To get out of this state, stopRecord, commit or reset must be
// called or the Player must change to a state other than STARTED
TInt64 time;
iPlayer->GetMediaTime(&time);
WaitForPauseL(time);
DoStopRecordL();
iState = ERecordStandBy;
break;
}
default:
{
LOG(EJavaMMAPI, EInfo, "MMA:CMMARecordControl::NextStateL: case default - code should not reach here!!");
__ASSERT_DEBUG(KErrGeneral, User::Invariant()); // This will newer occur
break;
}
}
}
// END OF FILE