自己负责一个类似来电显示的小软件,来电监听模块使用TAPI实现,之前一直不忙,日常工作只是版本维护。这次公司提出新需求,就想借这次机会,把来电监听模块重写。

  总结了一些Windows Mobile平台电话监听的几种实现方式:

  1.TAPI :此方法较为简单,脱离了底层硬件,协议统一,所以使用TAPI实现电话监听不会有特例性,各家手机均支持。但是TAPI所在层比较高,得到电话信息也就较慢一些。

  2.RIL: 硬件之上就是它了,最先得到电话信息,但是有OEM特性,各家实现方式不统一,所以不好匹配所有机型。不过使用它灵活性最大。所以如果使用RIL做电话监听,最大的问题就是如何去异求同。

  3.监控注册表: 所有电话信息都会写注册表,所以监控注册表也就成了电话监听的一种“歪门邪道”。这种方式肯定不能第一时间得到电话事件,并且需要不停的监控注册表,实在是下策。故不采用。

  4.AT指令:通过AT指令也可以实现(2010.9.26 更新)

 

  RIL的简单使用

sdk里是没有带ril库的,自己下载ril.lib。

把.h .lib添进工程

 

  1.实现这两个函数

void CALLBACK RilNotifyProc(DWORD dwNotifyCode, const void* pData, DWORD dwDataSize, DWORD dwParam);
void CALLBACK RilResultProc(DWORD dwResultCode, HRESULT hrCommandID, const void* pData, DWORD dwDataSize, DWORD dwParam);

  2.初始化RIL

HRIL       g_hRil;
HRESULT hr = RIL_Initialize(1, RilResultProc, RilNotifyProc, RIL_NCLASS_CALLCTRL, NULL, &g_hRil);

  3.卸载RIL

RIL_Deinitialize(g_hRil);

 

  测试RIL寻求共性

 

  测试发现Windows Mobile的一款手机(WM5.0),它只响应 RIL_NOTIFY_RING;RIL_NOTIFY_CONNECT;RIL_NOTIFY_DISCONNECT这3个事件,并且来电时,如果不接听则会连续产生RIL_NOTIFY_RING事件。当本机接听来电,则会产生RIL_NOTIFY_CONNECT事件。 不管哪方挂断电话产生RIL_NOTIFY_DISCONNECT事件。
经过模拟器,Windows Mobile5/6其它实机的测试,总结做来去电监听的思路如下:
对每个事件(RIL_NOTIFY_RING;RIL_NOTIFY_CONNECT;RIL_NOTIFY_DISCONNECT)只响应一次,假定A、B两方。

A给B打电话:A响应一次RIL_NOTIFY_CONNECT表示去电(除RIL_NOTIFY_DISCONNECT再不响应其它事件);B响应一次RIL_NOTIFY_RING表示来电(除RIL_NOTIFY_DISCONNECT再不响应其它事件)。

 

  贴出部分代码(不要觉得奇怪,没办法不同手机响应不同,所以写的比较奇怪。不能直接使用,只是让大家看一下逻辑,怎么实现共性的可以通用在不同手机上)

 



/*******************************************************
Copyright (C), 2010, tamer
FileName: CRilMonitor.cpp
Author: tamer Version : 1.0.0   Date: 2010/08/28
Description:   
Version: 1.0.0
Function List:

History: 
<author>    <time>   <version >   <desc>
 tamer 2010/08/28   1.0.0    build this moudle  
********************************************************/
#include <windows.h>
#include "CRilMonitor.h"


#pragma comment(lib, "ril/ril.lib")

#define RIL_CALLDIR_NONE (0x00000000)

CRilMonitor* CRilMonitor::s_pThis = NULL;

void CALLBACK CRilMonitor::RilResultProc(DWORD dwResultCode, HRESULT hrCommandID, const void* pData, DWORD dwDataSize, DWORD dwParam)
{  
	switch ( dwResultCode )   
	{   
	case RIL_RESULT_OK:   
		{  
			RILCALLINFO *pCallInfo = ((RILCALLINFO *)pData); // must call RIL_GetCallList

			if ( pCallInfo != NULL)  
			{
				if (RIL_CALLDIR_INCOMING == pCallInfo->dwDirection)
				{
					//DEBUGMSG(TRUE, (TEXT("Result status:%d\n"), pCallInfo->dwStatus));
					DEBUGMSG( TRUE, ( TEXT("来电号码:%s\n"), pCallInfo->raAddress.wszAddress) ); 
					_tcscpy(s_pThis->m_szPhoneNum, pCallInfo->raAddress.wszAddress);
					if (s_pThis->m_lpfnIncomingCall != NULL)
					{
						s_pThis->m_lpfnIncomingCall(s_pThis->m_szPhoneNum);
					}
				}
				if (RIL_CALLDIR_OUTGOING == pCallInfo->dwDirection)
				{
					DEBUGMSG( TRUE, ( TEXT("去电号码:%s\n"), pCallInfo->raAddress.wszAddress) );
					_tcscpy(s_pThis->m_szPhoneNum, pCallInfo->raAddress.wszAddress);
					if (s_pThis->m_lpfnDialingCall != NULL)
					{
						s_pThis->m_lpfnDialingCall(s_pThis->m_szPhoneNum);
					}
				}				  
			}  
			break;   
		}
	}  
}

void CALLBACK CRilMonitor::RilNotifyProc(DWORD dwNotifyCode, const void* pData, DWORD dwDataSize, DWORD dwParam)
{
	//DEBUGMSG(TRUE, (TEXT("RilNotifyCode:%d\n"), dwNotifyCode^RIL_NCLASS_CALLCTRL));
	switch(dwNotifyCode)
	{
	case RIL_NOTIFY_RING:
		if (!s_pThis->m_bFlag)
		{
			s_pThis->m_bFlag = TRUE;
			RIL_GetCallList( s_pThis->m_hRil );
		}
		break;
	case RIL_NOTIFY_CONNECT:
		if (!s_pThis->m_bFlag)
		{
			s_pThis->m_bFlag = TRUE;
			RIL_GetCallList( s_pThis->m_hRil );
		}
		break;
	case RIL_NOTIFY_DISCONNECT:
		if (s_pThis->m_bFlag)
		{
			s_pThis->m_bFlag = FALSE;
			DEBUGMSG(TRUE, (TEXT("挂断电话!\n")));
			if (s_pThis->m_lpfnDisconnectedCall != NULL)
			{
				s_pThis->m_lpfnDisconnectedCall(s_pThis->m_szPhoneNum);
			}
		}
		break;
	case RIL_NOTIFY_CALLSTATECHANGED:
		if (s_pThis->m_bFlag)
		{
			s_pThis->m_bFlag = FALSE;
			DEBUGMSG(TRUE, (TEXT("挂断电话!\n")));
			if (s_pThis->m_lpfnDisconnectedCall != NULL)
			{
				s_pThis->m_lpfnDisconnectedCall(s_pThis->m_szPhoneNum);
			}
		}
		break;
	case RIL_NOTIFY_CALLPROGRESSINFO:
		{		
			//DEBUGMSG(TRUE, (TEXT("Notify Direction:%d, status:%d\n"),prci->dwDirection, prci->dwStatus));
			if (s_pThis->m_bFlag)
			{
				RILCALLINFO* prci = (RILCALLINFO*)pData;
				if (RIL_CALLDIR_NONE == prci->dwDirection &&
					RIL_CALLSTAT_ALERTING == prci->dwStatus)
				{
					s_pThis->m_bFlag = FALSE;
					DEBUGMSG(TRUE, (TEXT("挂断电话!\n")));
					if (s_pThis->m_lpfnDisconnectedCall != NULL)
					{
						s_pThis->m_lpfnDisconnectedCall(s_pThis->m_szPhoneNum);
					}
				}
			}
		}
		break;
	}
}   



int CRilMonitor::InitMonitor(LPVOID lpParamer)
{
	HRESULT hr = RIL_Initialize(1, RilResultProc, RilNotifyProc, RIL_NCLASS_CALLCTRL/*RIL_NCLASS_ALL*/, NULL, &m_hRil);
	
	if (FAILED(hr))
	{
		DEBUGMSG(TRUE, (TEXT("RIL_Initialize err:%d\n"), GetLastError())); 
		return -1;
	}

	return 0;
}

void CRilMonitor::UninitMonitor(LPVOID lpParamer)
{
	RIL_Deinitialize(m_hRil);
	m_hRil = NULL;
}



 

 

只是简单的实现,其它功能还有待挖掘。

 

 

  几个重要的参数

/Call status values//
RIL_CALLSTAT_ACTIVE               Active call.
RIL_CALLSTAT_ONHOLD             Call on hold.
RIL_CALLSTAT_DIALING            In the process of dialing.
RIL_CALLSTAT_ALERTING            In the process of ringing.
RIL_CALLSTAT_INCOMING          Incoming (unanswered) call.
RIL_CALLSTAT_WAITING           Incoming call waiting call.

 

Call direction/
RIL_CALLDIR_INCOMING             Incoming call.
RIL_CALLDIR_OUTGOING             Outgoing call.