📄 ansphoneengine.cpp
字号:
/**
*
* @brief Definition of CAnsPhoneEngine
*
* Copyright (c) EMCC Software Ltd 2003
* @version 1.0
*/
#include "AnsPhoneEngine.h"
#include <bautils.h> // BaflUtils
#include <aknutils.h> // BaflUtils
_LIT(KYourMessageFileName, "\\system\\apps\\AnsPhone\\yourmes.wav");
_LIT(KTheirMessageFileName, "\\system\\apps\\AnsPhone\\theirmes.wav");
_LIT(KMessagesDir, "c:\\system\\apps\\AnsPhone\\messages\\");
_LIT(KTSY, "phonetsy");
_LIT(KMessageType, ".wav");
const TInt KSpace = 32;
const TInt KMaxMessages = 5;
const TInt KDelay = 10000;
const TInt KHalfSecond = 500000;
const TInt KGranMessages = 5;
CAnsPhoneEngine::CAnsPhoneEngine(MAnsPhoneEngineObserver& aObserver)
:iObserver(aObserver),
iState(ENoState),
iIsLocal(EFalse)
{
}
CAnsPhoneEngine::~CAnsPhoneEngine()
{
if (iTimer)
{
iTimer->Cancel();
delete iTimer;
}
SoundCleanup();
delete iMessageList;
TelephonyCleanup();
iFs.Close();
}
CAnsPhoneEngine* CAnsPhoneEngine::NewL(MAnsPhoneEngineObserver& aObserver)
{
CAnsPhoneEngine* self = new (ELeave) CAnsPhoneEngine(aObserver);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void CAnsPhoneEngine::ConstructL()
{
User::LeaveIfError(iFs.Connect());
// create the messages directory if it does not exist
if (!BaflUtils::PathExists(iFs, KMessagesDir))
User::LeaveIfError(iFs.MkDirAll(KMessagesDir));
iMessageList = new (ELeave) CArrayFixSeg<TMessage>(KGranMessages);
// load the messages from the messages directory
CDir* dir = NULL;
User::LeaveIfError(iFs.GetDir(KMessagesDir, KEntryAttNormal, ESortByDate|EDescending, dir));
CleanupStack::PushL(dir);
TInt numberFiles = dir->Count();
for(TInt a = 0; a < numberFiles; a++)
{
const TEntry& file = (*dir)[a];
TMessage message;
message.iNumber = file.iName;
message.iTime = file.iModified;
iMessageList->AppendL(message);
}
CleanupStack::PopAndDestroy(dir);
}
void CAnsPhoneEngine::MoscoStateChangeEventL(CBase* /*aObject*/, TInt /*aPreviousState*/, TInt aCurrentState, TInt aErrorCode)
{
// if the recording has died, this means that the recording should be finished;
// should only happen when recording on the telephony line
if(iState == ERecord && !iIsLocal && aErrorCode == KErrDied)
{
Stop();
return;
}
User::LeaveIfError(aErrorCode);
if(aCurrentState != CMdaAudioClipUtility::EOpen)
return;
switch(iState)
{
case ERecordInit:
// Record from the telephony line and set to max gain
if(iIsLocal)
{
iSound->SetAudioDeviceMode(CMdaAudioRecorderUtility::ELocal);
iSound->SetGain(iSound->MaxGain());
}
else
{
iSound->SetAudioDeviceMode(CMdaAudioRecorderUtility::ETelephonyNonMixed);
TInt maxGain = iSound->MaxGain();
iSound->SetGain(maxGain / 2);
}
// Delete current audio sample from beginning of file
iSound->SetPosition(TTimeIntervalMicroSeconds(0));
iSound->CropL();
// start recording
iSound->RecordL();
iState = ERecord;
break;
case ERecord:
break;
case EPlayInit:
{
// Play through the device speaker and set to max volume
if(iIsLocal)
{
iSound->SetAudioDeviceMode(CMdaAudioRecorderUtility::ELocal);
}
else
{
iSound->SetAudioDeviceMode(CMdaAudioRecorderUtility::ETelephonyOrLocal);
// iPhone.DeviceSpeakerOff();
}
iSound->SetVolume(iSound->MaxVolume());
// Set the playback position to the start of the file
iSound->SetPosition(TTimeIntervalMicroSeconds(0));
iSound->PlayL();
iState = EPlay;
// we start the timer
// add a half a second onto the play time to make sure we've finished playing
TInt64 playTime = iSound->Duration().Int64() + KHalfSecond;
if (iTimer)
{
delete iTimer;
iTimer = NULL;
}
iTimer = CAnsPhoneTimer::NewL(*this, playTime.GetTInt());
break;
}
default:
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// MMdaObjectStateChangeObserver
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CAnsPhoneEngine::MoscoStateChangeEvent(CBase* aObject, TInt aPreviousState, TInt aCurrentState, TInt aErrorCode)
// this function is called by the CMdaAudioRecorderUtility object
// it handles starting playing/recording and stopping the recording when the call has ended
//
// Note:
// When the CMdaAudioRecorderUtility plays/records a message, the function SetAudioDeviceMode()
// sets how the device mixes the microphone and telephony downlink
// CMdaAudioRecorderUtility::ETelephonyNonMixed should there should be no mixing between
// device speaker/microphone and the telephony downlink. However, this does not work and so
// when playing/recording during a call, the sound microphone is mixed with the telephony downlink
// One way to prevent this for recording is to set the volume to zero; this means the user cannot
// hear what the other person is recording. This cannot be done when playing because the downlink
// will have a volume of zero as well.
{
TRAPD (err, MoscoStateChangeEventL(aObject, aPreviousState, aCurrentState, aErrorCode))
if (err)
{
Stop();
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// MAnsPhoneTimerObserver
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CAnsPhoneEngine::TimerCompleteL()
// play has finished, so either alert the observer or start recording
{
// check for having cancelled the playing/recording before they have finished
// this will happen if the person hangs up before the playing has finished
if(iState == ENoState)
return;
delete iTimer;
iTimer = NULL;
iState = ENoState;
SoundCleanup();
if(iIsLocal)
{
iObserver.HandlePlayMessageOverL();
}
else
{
TMessage message;
TTime time;
time.HomeTime();
message.iTime = time;
iMessageList->InsertL(0, message);
RecordMessageL(EFalse);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// MAnsPhoneCallWatcherObserver
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CAnsPhoneEngine::HandleCallInChangeL(const RCall::TStatus& aStatus)
{
switch(aStatus)
{
case RCall::EStatusConnected:
{
iObserver.HandleCallChangeL(aStatus);
PlayMessageL(EFalse, 0, ETrue);
break;
}
case RCall::EStatusHangingUp:
// if we have started recording, then tell the observer that we have recorded a new message
if(iState == ERecord)
{
iObserver.HandleNewMessageL();
iCallLog->GetNumberL();
}
// if we have initialized recording without yet recording and the call is hung up,
// then we want to delete the file we have just created
else if(iState == ERecordInit)
{
iMessageList->Delete(0);
}
SoundCleanup();
iObserver.HandleCallChangeL(aStatus);
break;
default:
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// MAnsPhoneCallMakerObserver
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CAnsPhoneEngine::HandleCallHungUpL()
{
iObserver.HandleCallChangeL(RCall::EStatusUnknown);
delete iCallMaker;
iCallMaker = NULL;
if(!iCallWatcher)
{
iLine.Close();
iSession.Close();
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// MAnsPhoneCallLogObserver
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CAnsPhoneEngine::HandlePhoneNumberL(const TDesC& aNumber)
// the logger has completed with the phone number that called, so
// copy the file to the new name for the number and update the messages list with this new name
{
// get the next file in the list
TFileName file;
GetNextMessageFileName(file, aNumber);
TMessage& message = iMessageList->At(0);
message.iNumber = file;
file.Insert(0, KMessagesDir);
TFileName fileName (KTheirMessageFileName);
CompleteWithAppPath (fileName);
iFs.Rename(fileName, file);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CAnsPhoneEngine::AnsweringStartL()
// starts the answering machine
{
TelStartL();
iCallWatcher = CAnsPhoneCallWatcher::NewL(*this, iLine);
iCallLog = CAnsPhoneCallLog::NewL(*this);
}
void CAnsPhoneEngine::AnsweringStop()
// stops the answering machine
{
TelephonyCleanup();
}
void CAnsPhoneEngine::PlayMessageL(TBool aIsLocal, TInt aIndex, TBool aIsUsers)
{
SoundCleanup();
iSound = CMdaAudioRecorderUtility::NewL(*this);
if(aIsUsers)
{
TFileName fileName (KYourMessageFileName);
CompleteWithAppPath (fileName);
iSound->OpenFileL(fileName);
}
else
{
TFileName file = iMessageList->At(aIndex).iNumber;
file.Insert(0, KMessagesDir);
iSound->OpenFileL(file);
}
iState = EPlayInit;
iIsLocal = aIsLocal;
}
void CAnsPhoneEngine::RecordMessageL(TBool aIsLocal)
// records a message;
// if aIsLocal = ETrue, then record to the user's message; use the telephony line
// if aIsLocal = EFalse, then record to aFileName; use the device microphone
//
// there are several ways to record to a file by the CMdaAudioRecorderUtility:
// -> use OpenFileL()
// if we use this method, then the file must all ready exist, and just creating a new file using
// RFile.CreateL() or RFile.ReplaceL() will not be accepted by the recorder utility
// therefore, this would put a limit on how many messages could be kept
// -> use OpenL()
// if we use this method, then the file name passed to it, will lead it to construct a new file
// with this filename or it will overwrite an existing file with that name
// however, in order to use this function, we need to pass in several objects:
// -> file location
// -> file format to be recorded, this is populated by the function
// -> recording codec to use
// -> audio settings, such as sample rate and number of channels
{
SoundCleanup();
iSound = CMdaAudioRecorderUtility::NewL(*this);
iMessageCodec.iBits = TMdaPcmWavCodec::E16BitPcm;
iMessageSettings.iCaps = TMdaAudioDataSettings::ESampleRateFixed | TMdaAudioDataSettings::ESampleRate8000Hz | TMdaAudioDataSettings::EChannelsMono;
iMessageSettings.iSampleRate = 8000;
iMessageSettings.iChannels = 1;
if(aIsLocal)
{
TFileName fileName (KYourMessageFileName);
CompleteWithAppPath (fileName);
iMessageLocation.iName = fileName;
}
else
{
TFileName fileName (KTheirMessageFileName);
CompleteWithAppPath (fileName);
iMessageLocation.iName = fileName;
}
iSound->OpenL(&iMessageLocation, &iMessageFormat, &iMessageCodec, &iMessageSettings);
iState = ERecordInit;
iIsLocal = aIsLocal;
}
void CAnsPhoneEngine::Stop()
{
SoundCleanup();
}
void CAnsPhoneEngine::TelStartL()
// starts the telephony server and line;
// this does not start up the call watcher
// this is used when dialling
{
// if the call watcher is up and running, then we have all ready started the telephony server and line
if(iCallWatcher)
return;
User::LeaveIfError(iSession.Connect());
// load the appropriate tsy
User::LeaveIfError(iSession.LoadPhoneModule(KTSY));
// in order to get a handle on a line, we must get a handle on an RPhone object
TInt numberPhones = 0;
User::LeaveIfError(iSession.EnumeratePhones(numberPhones));
if(!numberPhones)
User::Leave(KErrNotFound);
// we use the 1st available phone
RTelServer::TPhoneInfo phoneInfo;
User::LeaveIfError(iSession.GetPhoneInfo(0, phoneInfo));
User::LeaveIfError(iPhone.Open(iSession, phoneInfo.iName));
// we must now find a line that will accept voice calls
TInt numberLines = 0;
User::LeaveIfError(iPhone.EnumerateLines(numberLines));
RPhone::TLineInfo lineInfo;
TBool foundLine = EFalse;
for(TInt a = 0; a < numberLines; a++)
{
User::LeaveIfError(iPhone.GetLineInfo(a, lineInfo));
if(lineInfo.iLineCapsFlags & RLine::KCapsVoice)
{
foundLine = ETrue;
break;
}
}
if(!foundLine)
User::Leave(KErrNotFound);
User::LeaveIfError(iLine.Open(iPhone, lineInfo.iName));
}
void CAnsPhoneEngine::SoundCleanup()
{
if(iSound)
{
iSound->Stop();
iSound->Close();
delete iSound;
iSound = NULL;
}
iState = ENoState;
}
void CAnsPhoneEngine::TelephonyCleanup()
{
delete iCallWatcher;
iCallWatcher = NULL;
delete iCallMaker;
iCallMaker = NULL;
delete iCallLog;
iCallLog = NULL;
iPhone.Close();
iLine.Close();
iSession.Close();
}
void CAnsPhoneEngine::DeleteMessage(TInt aIndex)
{
TFileName file;
file.Append(KMessagesDir);
file.Append(iMessageList->At(aIndex).iNumber);
iFs.Delete(file);
iMessageList->Delete(aIndex);
}
void CAnsPhoneEngine::GetNextMessageFileName(TDes& aFileName, const TDesC& aNumber)
// works out what the appropriate file name is for the next message to be recorded
{
TBool foundNumber = EFalse;
TInt highestIndex = 0;
TInt numberMessages = iMessageList->Count();
for(TInt a = 0; a < numberMessages; a++)
{
const TMessage& message = iMessageList->At(a);
TInt index = 0;
TBuf<KNumberMaxLength> buf;
TrimIndex(message.iNumber, buf, index);
if(aNumber.Compare(buf) == 0)
{
foundNumber = ETrue;
if(index > highestIndex)
highestIndex = index;
}
}
if(!foundNumber)
{
aFileName = aNumber;
}
else
{
aFileName = aNumber;
aFileName.Append(KSpace);
aFileName.AppendNum(highestIndex + 1);
}
}
void CAnsPhoneEngine::TrimIndex(const TDesC& aBuffer, TDes& aNumber, TInt& aIndex)
// takes aBuffer and works out the number from this and aIndex and populates these arguments
// e.g. "07779238045 5" gives aNumber = "07779239045" and aIndex = 5
{
TInt locateSpace = aBuffer.LocateReverse(KSpace);
if(locateSpace <= 0)
{
aNumber = aBuffer;
aIndex = 0;
}
else
{
aNumber = aBuffer.Left(locateSpace);
TBuf<KNumberMaxLength> buf = aBuffer.Right(aBuffer.Length() - locateSpace - 1);
TLex lex(buf);
lex.Val(aIndex);
}
}
void CAnsPhoneEngine::DialNumberL(TInt aIndex)
// dials the number of the message's number at aIndex in iMessageList
{
TelStartL();
iCallMaker = CAnsPhoneCallMaker::NewL(*this, iLine);
TBuf<KNumberMaxLength> file = iMessageList->At(aIndex).iNumber;
TBuf<KNumberMaxLength> number;
TInt index = 0;
TrimIndex(file, number, index);
iCallMaker->MakeCallL(number);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -