#ifndef _DIALENGINE_H_
#define _DIALENGINE_H_
// 注:这个类的使用需要能力NetworkServices和NetworkControl
#include <etel.h> // need etel.lib
class MPhoneCallClientObserver
{
public:
virtual void HandleCallHungUpL() = 0;
};
class CDialEngine: public CActive
{
public:
static CDialEngine* NewL(MPhoneCallClientObserver& aObserver);
~CDialEngine();
public:
// CActive
virtual void RunL();
virtual void DoCancel();
public:
void MakeCallL(const TDesC& aNumber);
private:
// the state of this object governs what happens when the
// StartL() / Stop() / RunL() / DoCancel() functions are called.
enum TState
{
ENoState, EDialling, EWatching
};
private:
CDialEngine(MPhoneCallClientObserver& aObserver);
void ConstructL();
private:
void StartL();
void Stop();
void InitCallServerL();
void TelephonyCleanup();
private:
MPhoneCallClientObserver& iObserver;
RTelServer iServer;
RPhone iPhone;
RLine iLine;
RCall iCall;
RCall::TStatus iCallStatus;
TState iState;
TPtrC iNumber;
};
#endif // _DIALENGINE_H_
#include "DialEngine.h"
_LIT(KTsyName,"phonetsy.tsy");
CDialEngine::CDialEngine(MPhoneCallClientObserver& aObserver) :
CActive(EPriorityNormal), iObserver(aObserver), iState(ENoState)
{
}
CDialEngine::~CDialEngine()
{
Cancel();
TelephonyCleanup();
}
CDialEngine* CDialEngine::NewL(MPhoneCallClientObserver& aObserver)
{
CDialEngine* self = new (ELeave) CDialEngine(aObserver);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void CDialEngine::ConstructL()
{
CActiveScheduler::Add(this);
InitCallServerL();
}
void CDialEngine::MakeCallL(const TDesC& aNumber)
{
iNumber.Set(aNumber);
iState = EDialling;
StartL();
}
void CDialEngine::InitCallServerL()
{
iServer.Connect();
iServer.LoadPhoneModule(KTsyName);
//Find the number of phones available from the tel server
TInt numberPhones;
User::LeaveIfError(iServer.EnumeratePhones(numberPhones));
//Check there are available phones
if (numberPhones < 1) {
User::Leave(KErrNotFound);
}
//Get info about the first available phone
RTelServer::TPhoneInfo info;
User::LeaveIfError(iServer.GetPhoneInfo(0, info));
//Use this info to open a connection to the phone, the phone is identified by its name
User::LeaveIfError(iPhone.Open(iServer, info.iName));
//Get info about the first line from the phone
RPhone::TLineInfo lineInfo;
User::LeaveIfError(iPhone.GetLineInfo(0, lineInfo));
//Use this to open a line
User::LeaveIfError(iLine.Open(iPhone, lineInfo.iName));
User::LeaveIfError(iCall.OpenNewCall(iLine));
}
void CDialEngine::StartL()
{
switch (iState) {
case ENoState:
return;
case EDialling:
{
iCall.Dial(iStatus, iNumber);
break;
}
case EWatching:
iCall.NotifyStatusChange(iStatus, iCallStatus);
break;
}
SetActive();
}
void CDialEngine::RunL()
{
// if the caller hangs up, then we will get KErrGeneral error here
if (iState == EDialling && iStatus.Int() == KErrGeneral) {
Stop();
iObserver.HandleCallHungUpL();
return;
}
if (iStatus.Int() != KErrNone)
return;
switch (iState) {
case EDialling:
iState = EWatching;
StartL();
break;
case EWatching:
User::LeaveIfError(iCall.GetStatus(iCallStatus));
if (iCallStatus == RCall::EStatusHangingUp || iCallStatus == RCall::EStatusIdle) {
Stop();
iObserver.HandleCallHungUpL();
}
else {
StartL();
}
break;
default:
break;
}
}
void CDialEngine::DoCancel()
{
Stop();
}
void CDialEngine::Stop()
{
switch (iState) {
case ENoState:
break;
case EDialling:
iCall.HangUp();
break;
case EWatching:
iCall.NotifyStatusChangeCancel();
break;
}
iState = ENoState;
}
void CDialEngine::TelephonyCleanup()
{
iCall.Close();
iLine.Close();
iPhone.Close();
iServer.Close();
}