⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ansphoneengine.cpp

📁 s60 接打电话代码,很有学习价值的,可以移植到不同平台
💻 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 + -