TAPI для Windows Mobile
Телефония в смартфоне и карманном ПК
Существует два класса мобильных устройств, которые обладают функциями телефона и, соответственно, поддерживают интерфейс телефонии: смартфоны и гибридные карманные ПК (Pocket PC) с поддержкой телефонии, реализуемой в Windows Mobile (WM) через интерфейс TAPI.
Под телефонией в данном случае понимается не только обычные голосовые звонки, но и VoIP связь, управление журналом звонков, организация конференций, передача данных по ISDN/ADSL сетям, получение сервисной информации о линии или звонке и многое другое.
Telephony API
Обзор
Мобильные устройства на платформе WM CE поддерживают интерфейс телефонии Microsoft API (TAPI 2.0) и частично TAPI 2.1. TAPI – это API, который значительно упрощает процесс соединения двух и более устройств. Абстракции TAPI для управления вызовами облегчают работу с, казалось бы, разными протоколами взаимодействия посредством абстракций под названием Telephony Service Provider (TSP).
Windows CE устройство по умолчанию поставляется с одним TSP – Unimodem Service Provider – провайдер универсального модема, которым можно управлять, используя AT команды. Тем не менее интерфейс TAPI позволяет инсталлировать дополнительные TSP сторонних разработчиков, чтобы обеспечить поддержку VoIP, H.323 (голосовые и видеоконференции), SIP, ISDN, сотовой связи и пр.
TAPI – совместная разработка компании Microsoft и Intel. TAPI находит широкое применение как в приложениях под PC на базе MS Windows, так и в в приложениях, работающих под управлением Windows CE. TAPI 2.1 CE – это значительно сокращенная версия полнофункциональной библиотеки телефонии TAPI 3.0. Схема TAPI 3.0 для Win 32 платформы приведена ниже:

Рис. 1 Детализированная схема TAPI 3
Схема TAPI CE несколько скромнее, по умолчанию здесь присутствует только один TSP:
Рис. 2 Интерфейс и компоненты Win CE TAPI. Укрупненная схема.
TAPI для мобильных телефонов делится на 5 подмножеств: Assisted API, Extended API, Phone API, Telephony API и TSP API. Рассмострим каждый из них в отдельности.
CE TAPI
Assisted TAPI
Assisted TAPI – данное подмножество состоит из единственного метода для выполнения обычного голосового звонка.
-
LONG tapiRequestMakeCall (
-
LPCTSTR lpszDestAddress,
-
LPCTSTR lpszAppName = NULL,
-
LPCTSTR lpszCalledParty,
-
LPCTSTR lpszComment = NULL
-
);
Header: astdtapi.h
Library: cellcore.lib
Примечание: ввиду различной реализации Assisted TAPI звонка и звонка через полнофункциональную Telephony API, не рекомендуется смешивать в одном приложении оба способа вызова адресата.
В карманных ПК Assisted TAPI работает только в CDMA сети.
2.2.2. Extended TAPI
Extended TAPI – интерфейс для работы с беспроводным интерфейсом: запрос мощности сигнала, состояние передатчика и приемника, выбор оператора сотовой связи и пр. С помощью Extended API можно работать с CDMA, GSM, GPRS интерфейсами.
Все операции выполняются через сервис работы с линией.
Примеры методов:
-
LONG WINAPI lineGetGeneralInfo(
-
HLINE hLine,
-
LPLINEGENERALINFO lpLineGeneralInfo
-
);
-
-
typedef struct linegeneralinfo_tag {
-
DWORD dwTotalSize;
-
DWORD dwNeededSize;
-
DWORD dwUsedSize;
-
DWORD dwManufacturerSize;
-
DWORD dwManufacturerOffset;
-
DWORD dwModelSize;
-
DWORD dwModelOffset;
-
DWORD dwRevisionSize;
-
DWORD dwRevisionOffset;
-
DWORD dwSerialNumberSize;
-
DWORD dwSerialNumberOffset;
-
DWORD dwSubscriberNumberSize;
-
DWORD dwSubscriberNumberOffset;
-
} LINEGENERALINFO, * LPLINEGENERALINFO;
-
-
LONG WINAPI lineGetCurrentOperator(
-
HLINE hLine,
-
LPLINEOPERATOR lpCurrentOperator
-
);
-
-
typedef struct lineoperator_tag {
-
DWORD dwIndex;
-
DWORD dwValidFields;
-
DWORD dwStatus;
-
TCHAR lpszLongName[MAX_LENGTH_OPERATOR_LONG];
-
TCHAR lpszShortName[MAX_LENGTH_OPERATOR_SHORT];
-
TCHAR lpszNumName[MAX_LENGTH_OPERATOR_NUMERIC];
-
} LINEOPERATOR, * LPLINEOPERATOR;
Всего определено около 30 функций.
Header: extapi.h.
Library: сellcore.lib
Phone API
Phone API – интерфейс для работы с журналом вызовов (Call Log), а также со временем и оплатой вызовов (Billing). Данное подмножество TAPI имеет наибольшее практическое применение.
Все входящие, исходящие, пропущенные звонки сохраняются во внутренней таблице журнала вызовов. С помощью функций Phone API можно получать информацию о звонках из этой таблицы, фильтровать, сортировать, удалять и пр.
Данный интерфейс поддерживается только в смартфонах и гибридных карманных ПК.
Функции Phone API:
- PhoneAddSpeedDial – добавить запись в таблицу быстрого набора
- PhoneMakeCall – позвонить
- PhoneOpenCallLog – открыть журнал вызовов
- PhoneGetCallLogEntry – получить журнал вызовов
- PhoneCloseCallLog – закрыть журнал вызовов
- PhoneSeekCallLog – позиционировать в журнале вызовов на определенную запись
- PhoneShowCallLog – показывает Call Log с указанным фильтром
Работа с журналом вызовов схожа с работой с типизированными файлами, где каждая запись – это структура. Вначале необходимо открыть Call Log, получив дескриптор. Затем с помощью функции PhoneGetCallLogEntry читать последовательно по записи. В конце работы с журналом – закрыть его.
Есть возможность позиционировать маркер в файле на определенную запись.
С помощью позиционирования можно также получить общее кол-во записей в журнале.
Прототип функции извлечения записи журнала вызовов:
-
HRESULT PhoneGetCallLogEntry(
-
HANDLE h,
-
PCALLLOGENTRY pentry
-
);
-
-
typedef struct {
-
DWORD cbSize;
-
FILETIME ftStartTime;
-
FILETIME ftEndTime;
-
IOM iom;
-
BOOL fOutgoing:1;
-
BOOL fConnected:1;
-
BOOL fEnded:1;
-
BOOL fRoam:1;
-
CALLERIDTYPE cidt;
-
PTSTR pszNumber;
-
PTSTR pszName;
-
PTSTR pszNameType;
-
PTSTR pszNote;
-
} CALLLOGENTRY, * PCALLLOGENTRY;
Из журнала вызовов можно извлечь следующую информацию:
- Время начала звонка
- Время окончания звонка
- Тип: входящий принятый, входящий пропущенный, исходящий
- Как закончился звонок: штатно или был сброшен
- Звонок в Home Area или в роуминге
- Информация о CallerID: доступна, заблокирована, не доступна
- Номер абонента
- Имя абонента
- Тип телефона абонента: домашний, рабочий (из адресной книги)
Header: phone.h
Library: phone.lib
Telephony API
Telephony API состоит из двух интерфейсов: работа с линией и работа с телефоном.
Телефон
Телефон – это абстракция, описывающая микрофон, динамик, модуль беспроводной связи и т.д.
С помощью функций для работы с телефоном можно как получить статус телефона, настройки вызова, состояние спикерфона, так и изменить настройки.
Например,
-
LONG WINAPI phoneGetStatus(
-
HPHONE hPhone,
-
LPPHONESTATUS lpPhoneStatus
-
);
-
-
typedef struct phonestatus_tag {
-
DWORD dwTotalSize;
-
DWORD dwNeededSize;
-
DWORD dwUsedSize;
-
DWORD dwStatusFlags;
-
DWORD dwNumOwners;
-
DWORD dwNumMonitors;
-
DWORD dwRingMode;
-
DWORD dwRingVolume;
-
DWORD dwHandsetHookSwitchMode;
-
DWORD dwHandsetVolume;
-
DWORD dwHandsetGain;
-
DWORD dwSpeakerHookSwitchMode;
-
DWORD dwSpeakerVolume;
-
DWORD dwSpeakerGain;
-
DWORD dwHeadsetHookSwitchMode;
-
DWORD dwHeadsetVolume;
-
DWORD dwHeadsetGain;
-
DWORD dwDisplaySize;
-
DWORD dwDisplayOffset;
-
DWORD dwLampModesSize;
-
DWORD dwLampModesOffset;
-
DWORD dwOwnerNameSize;
-
DWORD dwOwnerNameOffset;
-
DWORD dwDevSpecificSize;
-
DWORD dwDevSpecificOffset;
-
DWORD dwPhoneFeatures;
-
} PHONESTATUS, FAR* LPPHONESTATUS;
Наиболее полезные с практической точки зрения функции:
- phoneConfigDialog – открыть диалог настроек телефона
- phoneGetDevCaps – получить данные о TAPI и телефоне (версия, DeviceID…)
- phoneGetGain/phoneSetGain – получить /установить уровень чувствительности микрофона
- phoneGetMessage – получить следующее сервисное сообщение TAPI
- phoneGetStatus – получить статус телефона
- phoneGetRing/phoneSetRing – получить/установить тип звонка и громкость
Всего чуть больше 20 функций.
Header: tapi.h.
Library: coredll.lib.
Линия
Под линией понимается абстракция, обозначающая телефонную линию. Она может содержать один или несколько коммуникационных каналов. В большинстве случаев обстракции ‘линия’ и ‘телефон’ имеют отношение “один к одному”. Но возможны случаи, когда одна линия связана с несколькими телефонами (в случае ISDN).
С помощью функций для работы с линией можно ‘звонить’, отвечать на вызовы, выполнять переадресацию, удерживать абонента на линии, организовывать конференции, получать статус линии и конфигурировать ее.
Например,
-
LONG WINAPI lineAnswer(
-
HCALL hCall,
-
LPCSTR lpsUserUserInfo,
-
DWORD dwSize
-
);
-
-
LONG WINAPI lineDial(
-
HCALL hCall,
-
LPCWSTR lpszDestAddress,
-
DWORD dwCountryCode
-
);
-
-
LONG WINAPI lineGetCallInfo(
-
HCALL hCall,
-
LPLINECALLINFO lpCallInfo
-
);
-
-
typedef struct linecallinfo_tag {
-
DWORD dwTotalSize;
-
DWORD dwNeededSize;
-
DWORD dwUsedSize;
-
HLINE hLine;
-
DWORD dwLineDeviceID;
-
DWORD dwAddressID;
-
DWORD dwBearerMode;
-
DWORD dwRate;
-
DWORD dwMediaMode;
-
DWORD dwAppSpecific;
-
DWORD dwCallID;
-
DWORD dwRelatedCallID;
-
DWORD dwCallParamFlags;
-
DWORD dwCallStates;
-
DWORD dwMonitorDigitModes;
-
DWORD dwMonitorMediaModes;
-
LINEDIALPARAMS DialParams;
-
DWORD dwOrigin;
-
DWORD dwReason;
-
DWORD dwCompletionID;
-
DWORD dwNumOwners;
-
DWORD dwNumMonitors;
-
DWORD dwCountryCode;
-
DWORD dwTrunk;
-
DWORD dwCallerIDFlags;
-
DWORD dwCallerIDSize;
-
DWORD dwCallerIDOffset;
-
DWORD dwCallerIDNameSize;
-
DWORD dwCallerIDNameOffset;
-
DWORD dwCalledIDFlags;
-
DWORD dwCalledIDSize;
-
DWORD dwCalledIDOffset;
-
DWORD dwCalledIDNameSize;
-
DWORD dwCalledIDNameOffset;
-
DWORD dwConnectedIDFlags;
-
DWORD dwConnectedIDSize;
-
DWORD dwConnectedIDOffset;
-
DWORD dwConnectedIDNameSize;
-
DWORD dwConnectedIDNameOffset;
-
DWORD dwRedirectionIDFlags;
-
DWORD dwRedirectionIDSize;
-
DWORD dwRedirectionIDOffset;
-
DWORD dwRedirectionIDNameSize;
-
DWORD dwRedirectionIDNameOffset;
-
DWORD dwRedirectingIDFlags;
-
DWORD dwRedirectingIDSize;
-
DWORD dwRedirectingIDOffset;
-
DWORD dwRedirectingIDNameSize;
-
DWORD dwRedirectingIDNameOffset;
-
DWORD dwAppNameSize;
-
DWORD dwAppNameOffset;
-
DWORD dwDisplayableAddressSize;
-
DWORD dwDisplayableAddressOffset;
-
DWORD dwCalledPartySize;
-
DWORD dwCalledPartyOffset;
-
DWORD dwCommentSize;
-
DWORD dwCommentOffset;
-
DWORD dwDisplaySize;
-
DWORD dwDisplayOffset;
-
DWORD dwUserUserInfoSize;
-
DWORD dwUserUserInfoOffset;
-
DWORD dwHighLevelCompSize;
-
DWORD dwHighLevelCompOffset;
-
DWORD dwLowLevelCompSize;
-
DWORD dwLowLevelCompOffset;
-
DWORD dwChargingInfoSize;
-
DWORD dwChargingInfoOffset;
-
DWORD dwTerminalModesSize;
-
DWORD dwTerminalModesOffset;
-
DWORD dwDevSpecificSize;
-
DWORD dwDevSpecificOffset;
-
} LINECALLINFO, FAR* LPLINECALLINFO;
Всего около 50 функций.
Header: tapi.h.
Library: coredll.lib.
Telephony Service Provider (TSP) API
TSP API – это прослойка между Win CE TAPI интерфейсом, с которым работает разработчик и устройством, через которое происходит взаимодействие с внешним миром, оформленная в виде DLL. Верхний уровень TSP предоставляет разработчику унифицированный интерфейс, а низкоуровневый интерфейс TSP работает непосредственно с устройством.
Алгоритм работы
Рассмотрим пример работы с TAPI:
Инициализация линии
-
LONG WINAPI lineInitialize(
-
LPHLINEAPP lphLineApp,
-
HINSTANCE hInstance,
-
LINECALLBACK lpfnCallback,
-
LPCWSTR lpszAppName,
-
LPDWORD lpdwNumDevs
-
);
Данная функция принимает callback функцию, через которую приложение нотифицируется о входящих звонках, изменениях состояния линии и пр.
Фрагмент инициализации TAPI:
-
VOID CALLBACK lineCallbackFunc(
-
DWORD hDevice,
-
DWORD dwMsg,
-
DWORD dwCallbackInstance,
-
DWORD dwParam1,
-
DWORD dwParam2,
-
DWORD dwParam3)
-
{
-
…
-
switch (dwMsg)
-
{
-
case LINE_CALLSTATE: // Sent after change of call state
-
-
// dwParam1 is the specific CALLSTATE change that is occurring.
-
switch (dwParam1)
-
{
-
case LINECALLSTATE_DIALTONE:
-
lpszStatus = TEXT("Dial tone");
-
break;
-
-
case LINECALLSTATE_DIALING:
-
lpszStatus = TEXT("Dialing…");
-
break;
-
-
case LINECALLSTATE_PROCEEDING:
-
lpszStatus = TEXT("Dialing completed, call proceeding.");
-
break;
-
-
case LINECALLSTATE_RINGBACK:
-
lpszStatus = TEXT("Ring back");
-
break;
-
-
case LINECALLSTATE_CONNECTED:
-
lpszStatus = TEXT("Connected");
-
break;
-
-
case LINECALLSTATE_BUSY:
-
lpszStatus = TEXT("Line busy, shutting down.");
-
bCloseLine = TRUE;
-
break;
-
-
case LINECALLSTATE_IDLE:
-
lpszStatus = TEXT("Line is idle");
-
break;
-
-
case LINECALLSTATE_SPECIALINFO:
-
lpszStatus =TEXT("Special Information, couldn’t dial number");
-
bCloseLine = TRUE;
-
break;
-
-
case LINECALLSTATE_DISCONNECTED:
-
{
-
LPTSTR lpszDisconnected;
-
lpszDisconnected = TEXT(" ");
-
-
switch (dwParam2)
-
{
-
case LINEDISCONNECTMODE_NORMAL:
-
lpszDisconnected = TEXT("Remote party disconnected");
-
break;
-
-
case LINEDISCONNECTMODE_UNKNOWN:
-
lpszDisconnected = TEXT("Disconnected: Unknown reason");
-
break;
-
-
case LINEDISCONNECTMODE_REJECT:
-
lpszDisconnected = TEXT("Remote Party rejected call");
-
break;
-
-
case LINEDISCONNECTMODE_PICKUP:
-
lpszDisconnected =
-
TEXT("Disconnected: Local phone picked up");
-
break;
-
-
case LINEDISCONNECTMODE_FORWARDED:
-
lpszDisconnected = TEXT("Disconnected: Forwarded");
-
break;
-
-
case LINEDISCONNECTMODE_BUSY:
-
lpszDisconnected = TEXT("Disconnected: Busy");
-
break;
-
-
case LINEDISCONNECTMODE_NOANSWER:
-
lpszDisconnected = TEXT("Disconnected: No Answer");
-
break;
-
-
case LINEDISCONNECTMODE_BADADDRESS:
-
lpszDisconnected = TEXT("Disconnected: Bad address");
-
break;
-
-
case LINEDISCONNECTMODE_UNREACHABLE:
-
lpszDisconnected = TEXT("Disconnected: Unreachable");
-
break;
-
-
case LINEDISCONNECTMODE_CONGESTION:
-
lpszDisconnected = TEXT("Disconnected: Congestion");
-
break;
-
-
case LINEDISCONNECTMODE_INCOMPATIBLE:
-
lpszDisconnected = TEXT("Disconnected: Incompatible");
-
break;
-
-
case LINEDISCONNECTMODE_UNAVAIL:
-
lpszDisconnected = TEXT("Disconnected: Unavailable");
-
break;
-
-
case LINEDISCONNECTMODE_NODIALTONE:
-
lpszDisconnected = TEXT("Disconnected: No dial tone");
-
break;
-
-
default:
-
lpszDisconnected = TEXT("Disconnected: Unknown reason");
-
break;
-
} // end switch (dwParam2)
-
-
bCloseLine = TRUE;
-
wcscpy(lpszStatus,lpszDisconnected);
-
break;
-
} // end case LINECALLSTATE_DISCONNECTED:
-
} // end switch (dwParam1)
-
-
if (g_hwndDial)
-
SendDlgItemMessage(g_hwndDial, IDC_STATUSMESSAGE, WM_SETTEXT,
-
0,(LPARAM)lpszStatus);
-
-
if (bCloseLine)
-
{
-
CurrentLineClose ();
-
if (g_hwndDial)
-
-
SendMessage (g_hwndDial, WM_COMMAND, MAKEWPARAM(IDOK,0), 0);
-
}
-
break;
-
….
-
}
-
-
HLINEAPP g_hLineApp;
-
…
-
DWORD dwNumDevices = 0;
-
DWORD dwRet = ::lineInitialize(&g_hLineApp,g_hInst,
-
(LINECALLBACK)LineCallbackFunc,
-
_T("Developer.com Test"),
-
&dwNumDevices);
-
-
if ( dwRet != 0 )
-
{
-
// Report error
-
}
Для завершения работы с линией, ее нужно деинициализировать.
-
lReturn = ::lineShutdown(m_hLineApp);
Ссылки
- http://msdn.microsoft.com/en-us/library/aa454282.aspx
- “Chapter 8. Pocket PC Phone Edition”
Pocket PC Network Programming, By Steve Makofsky
Publisher : Addison Wesley
Pub Date : July 11, 2003
ISBN : 0-321-13352-8
Pages : 656
(c) 2008 Г. Земсков


