1 /*
2 * MobileOpalDlg.h
3 *
4 * Sample Windows Mobile application.
5 *
6 * Open Phone Abstraction Library
7 *
8 * Copyright (c) 2008 Vox Lucida
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is Open Phone Abstraction Library.
21 *
22 * The Initial Developer of the Original Code is Vox Lucida (Robert Jongbloed)
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Revision: 23896 $
27 * $Author: rjongbloed $
28 * $Date: 2009-12-23 16:49:19 -0600 (Wed, 23 Dec 2009) $
29 */
30
31 #include "stdafx.h"
32 #include "MobileOPAL.h"
33 #include "MobileOpalDlg.h"
34 #include "OptionsGeneral.h"
35 #include "OptionsCodecs.h"
36 #include "OptionsH323.h"
37 #include "OptionsSIP.h"
38
39 #include <winsock2.h>
40 #include <iphlpapi.h>
41 #include <pmpolicy.h>
42 #include <pm.h>
43
44
45 #ifdef _DEBUG
46 #define new DEBUG_NEW
47 #endif
48
49 #define SPEAKERMODE_METHOD 3
50
51
52 #define TRACE_OPTIONS "TraceLevel=4 TraceFile=\\MobileOpalLog.txt"
53 //#define TRACE_OPTIONS "TraceLevel=3 TraceAppend TraceFile=\\MobileOpalLog.txt"
54
55
56 static UINT TimerID = 1;
57
58 static TCHAR const RecentCallsSection[] = L"RecentCalls";
59 static TCHAR const OptionsSection[] = L"Options";
60 static TCHAR const UserNameKey[] = L"UserName";
61 static TCHAR const DisplayNameKey[] = L"DisplayName";
62 static TCHAR const STUNServerKey[] = L"STUNServer";
63 static TCHAR const MediaOrderKey[] = L"MediaOrder";
64 static TCHAR const MediaMaskKey[] = L"MediaMask";
65 static TCHAR const MediaOptionsKey[] = L"MediaOptions";
66 static TCHAR const InterfaceAddressKey[] = L"InterfaceAddress";
67 static TCHAR const AutoStartTxVideoKey[] = L"AutoStartTxVideo";
68 static TCHAR const GkTypeKey[] = L"GatekeeperType";
69 static TCHAR const GkIdKey[] = L"GatekeeperIdentifer";
70 static TCHAR const GkHostKey[] = L"GatekeeperHost";
71 static TCHAR const GkAliasKey[] = L"GatekeeperAlias";
72 static TCHAR const GkAuthUserKey[] = L"GatekeeperUser";
73 static TCHAR const GkPasswordKey[] = L"GatekeeperPassword";
74 static TCHAR const RegistrarAorKey[] = L"RegistrarAOR";
75 static TCHAR const RegistrarHostKey[] = L"RegistrarHost";
76 static TCHAR const RegistrarUserKey[] = L"RegistrarUser";
77 static TCHAR const RegistrarPassKey[] = L"RegistrarPassword";
78 static TCHAR const RegistrarRealmKey[] = L"RegistrarRealm";
79
80 static TCHAR const DefaultMediaOrder[] = L"G.722.2\nGSM-AMR\nG.729\nG.729A\nG.723.1\nG.728\nG.711-uLaw-64k\nG.711-ALaw-64k\nH.264\nH.263\nH.261";
81 static TCHAR const DefaultMediaMask[] = L"RFC4175_RGB\nRFC4175_YCbCr-4\nMPEG4";
82 static TCHAR const DefaultMediaOptions[] = L"H.264:Level=1b";
83
84
GetOptionString(LPCTSTR szKey,LPCTSTR szDefault=NULL)85 static CString GetOptionString(LPCTSTR szKey, LPCTSTR szDefault = NULL)
86 {
87 return AfxGetApp()->GetProfileString(OptionsSection, szKey, szDefault);
88 }
89
90
GetOptionStringA(LPCTSTR szKey,LPCTSTR szDefault=NULL)91 static CStringA GetOptionStringA(LPCTSTR szKey, LPCTSTR szDefault = NULL)
92 {
93 CStringA str((const TCHAR *)AfxGetApp()->GetProfileString(OptionsSection, szKey, szDefault));
94 return str;
95 }
96
97
GetOptionInt(LPCTSTR szKey,int iDefault=0)98 static UINT GetOptionInt(LPCTSTR szKey, int iDefault = 0)
99 {
100 return AfxGetApp()->GetProfileInt(OptionsSection, szKey, iDefault);
101 }
102
103
SetOptionString(LPCTSTR szKey,LPCTSTR szValue)104 static void SetOptionString(LPCTSTR szKey, LPCTSTR szValue)
105 {
106 AfxGetApp()->WriteProfileString(OptionsSection, szKey, szValue);
107 }
108
109
SetOptionInt(LPCTSTR szKey,UINT szValue)110 static void SetOptionInt(LPCTSTR szKey, UINT szValue)
111 {
112 AfxGetApp()->WriteProfileInt(OptionsSection, szKey, szValue);
113 }
114
115
GetNetworkInterfaces(CStringArray & interfaces,bool includeNames)116 void GetNetworkInterfaces(CStringArray & interfaces, bool includeNames)
117 {
118 // Get interfaces
119 BYTE * buffer = NULL;
120 ULONG size = 0;
121 DWORD error = GetIpAddrTable(NULL, &size, FALSE);
122 if (error == ERROR_INSUFFICIENT_BUFFER) {
123 buffer = new BYTE[size];
124 if (buffer != NULL)
125 error = GetIpAddrTable((MIB_IPADDRTABLE *)buffer, &size, FALSE);
126 }
127
128 if (error == ERROR_SUCCESS) {
129 const MIB_IPADDRTABLE * ipaddr = (const MIB_IPADDRTABLE *)buffer;
130 for (unsigned i = 0; i < ipaddr->dwNumEntries; ++i) {
131 in_addr ip;
132 ip.S_un.S_addr = ipaddr->table[i].dwAddr;
133 if (ntohl(ip.S_un.S_addr) != INADDR_LOOPBACK) {
134 CStringA iface;
135 if (ip.S_un.S_addr != INADDR_ANY)
136 iface = inet_ntoa(ip);
137
138 if (includeNames) {
139 MIB_IFROW info;
140 info.dwIndex = ipaddr->table[i].dwIndex;
141 if (GetIfEntry(&info) == NO_ERROR && info.dwDescrLen > 0) {
142 iface += '%';
143 iface.Append((const char *)info.bDescr, info.dwDescrLen);
144 }
145 }
146
147 if (!iface.IsEmpty())
148 interfaces.Add(CString(iface));
149 }
150 }
151 }
152 delete [] buffer;
153 }
154
155
156 #if SPEAKERMODE_METHOD==1
157
158 #define MM_WOM_FORCESPEAKER (WM_USER+2)
159
SetSpeakerMode(bool speakerphone)160 static void SetSpeakerMode(bool speakerphone)
161 {
162 MMRESULT result = waveOutMessage((HWAVEOUT)0, MM_WOM_FORCESPEAKER, speakerphone, 0);
163 if (result != MMSYSERR_NOERROR) {
164 wchar_t buffer[200];
165 wsprintf(buffer, L"Could not do speakerphone switch, error=%u", result);
166 AfxMessageBox(buffer);
167 }
168 }
169
170 #elif SPEAKERMODE_METHOD==2 || SPEAKERMODE_METHOD==5
171
172 /* Stuff from Wavedev.h */
173 #define IOCTL_WAV_MESSAGE 0x001d000c
174 typedef struct {
175 UINT uDeviceId;
176 UINT uMsg;
177 DWORD dwUser;
178 DWORD dwParam1;
179 DWORD dwParam2;
180 } MMDRV_MESSAGE_PARAMS;
181 /* End of Wavedev.h extract */
182
183
184 class WavDevice
185 {
186 private:
187 HANDLE hWavDev;
188
189 public:
WavDevice()190 WavDevice()
191 {
192 hWavDev = CreateFile(TEXT("WAV1:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
193 if (hWavDev == INVALID_HANDLE_VALUE) {
194 wchar_t buffer[200];
195 wsprintf(buffer, L"Could not open device, error=%u", GetLastError());
196 AfxMessageBox(buffer);
197 }
198 }
199
~WavDevice()200 ~WavDevice()
201 {
202 if (hWavDev != INVALID_HANDLE_VALUE)
203 CloseHandle(hWavDev);
204 }
205
SendMessage(UINT uMsg,DWORD dwParam1=0,DWORD dwParam2=0)206 bool SendMessage(UINT uMsg, DWORD dwParam1 = 0, DWORD dwParam2 = 0)
207 {
208 if (hWavDev == INVALID_HANDLE_VALUE)
209 return false;
210
211 DWORD dwRet = 0, dwOut;
212 MMDRV_MESSAGE_PARAMS mp;
213 memset(&mp,0,sizeof(mp));
214 mp.uMsg = uMsg;
215 mp.dwParam1 = dwParam1;
216 mp.dwParam2 = dwParam2;
217 if (DeviceIoControl(hWavDev, IOCTL_WAV_MESSAGE, &mp, sizeof(mp), &dwOut, sizeof(dwOut), &dwRet, 0))
218 return true;
219
220 wchar_t buffer[200];
221 wsprintf(buffer, L"Could not do speakerphone switch, error=%u", GetLastError());
222 AfxMessageBox(buffer);
223 return false;
224 }
225 };
226
227
SetSpeakerMode(bool speakerphone)228 static void SetSpeakerMode(bool speakerphone)
229 {
230 WavDevice wd;
231 #if SPEAKERMODE_METHOD==2
232 if (!wd.SendMessage(1002, speakerphone ? 0 : 2))
233 return;
234 if (!wd.SendMessage(1012, speakerphone ? 0 : 1))
235 return;
236 if (speakerphone && !wd.SendMessage(1013))
237 return;
238 wd.SendMessage(1000, speakerphone ? 2 : 4, speakerphone ? 0 : 7);
239 #else
240 wd.SendMessage(102, speakerphone);
241 #endif
242 }
243
244 #elif SPEAKERMODE_METHOD==3
245
246 class OsSvcsDll
247 {
248 private:
249 HMODULE hDLL;
250 typedef HRESULT (* SetSpeakerModeFn)(DWORD mode);
251 SetSpeakerModeFn pfnSetSpeakerMode;
252
253 public:
OsSvcsDll()254 OsSvcsDll()
255 {
256 hDLL = LoadLibrary(L"\\windows\\ossvcs.dll");
257 if (hDLL == NULL) {
258 wchar_t buffer[200];
259 wsprintf(buffer, L"Could not open DLL, error=%u", GetLastError());
260 AfxMessageBox(buffer);
261 }
262 pfnSetSpeakerMode = (SetSpeakerModeFn)GetProcAddress(hDLL, (LPCTSTR)218);
263 if (pfnSetSpeakerMode == NULL) {
264 wchar_t buffer[200];
265 wsprintf(buffer, L"Could not open DLL, error=%u", GetLastError());
266 AfxMessageBox(buffer);
267 }
268 }
269
~OsSvcsDll()270 ~OsSvcsDll()
271 {
272 if (hDLL != NULL)
273 FreeLibrary(hDLL);
274 }
275
SetSpeakerMode(DWORD speakerphone)276 bool SetSpeakerMode(DWORD speakerphone)
277 {
278 if (pfnSetSpeakerMode == NULL)
279 return false;
280
281 HRESULT result = pfnSetSpeakerMode(speakerphone);
282 if (result == 0)
283 return true;
284
285 wchar_t buffer[200];
286 wsprintf(buffer, L"Could not do speakerphone switch, error=0x%x", result);
287 AfxMessageBox(buffer);
288 return false;
289 }
290 };
291
292
SetSpeakerMode(bool speakerphone)293 static void SetSpeakerMode(bool speakerphone)
294 {
295 OsSvcsDll dll;
296 dll.SetSpeakerMode(speakerphone ? 1 : 0);
297 }
298
299 #elif SPEAKERMODE_METHOD==4
300
301 #include "ril.h"
302 #pragma comment(lib, "ril.lib")
303
ResultCallback(DWORD dwCode,HRESULT hrCmdID,const void * lpData,DWORD cbData,DWORD dwParam)304 static void CALLBACK ResultCallback(DWORD dwCode, // @parm result code
305 HRESULT hrCmdID, // @parm ID returned by the command that originated this response
306 const void* lpData, // @parm data associated with the notification
307 DWORD cbData, // @parm size of the strcuture pointed to lpData
308 DWORD dwParam // @parm parameter passed to <f RIL_Initialize>
309 )
310 {
311 }
312
NotifyCallback(DWORD dwCode,const void * lpData,DWORD cbData,DWORD dwParam)313 static void CALLBACK NotifyCallback(DWORD dwCode, // @parm notification code
314 const void* lpData, // @parm data associated with the notification
315 DWORD cbData, // @parm size of the strcuture pointed to lpData
316 DWORD dwParam // @parm parameter passed to <f RIL_Initialize>
317 )
318 {
319 }
320
SetSpeakerMode(bool speakerphone)321 static void SetSpeakerMode(bool speakerphone)
322 {
323 HRIL hRIL;
324 HRESULT result = RIL_Initialize(1, ResultCallback, NotifyCallback, RIL_NCLASS_MISC, 0, &hRIL);
325 if (result != S_OK) {
326 wchar_t buffer[200];
327 wsprintf(buffer, L"Could not open RIL, error=0x%x", result);
328 AfxMessageBox(buffer);
329 return;
330 }
331
332 RILAUDIODEVICEINFO info;
333 info.cbSize = sizeof(info);
334 info.dwParams = RIL_PARAM_ADI_ALL; // RIL_PARAM_ADI_TXDEVICE;
335 info.dwRxDevice = RIL_AUDIO_HANDSET;
336 info.dwTxDevice = speakerphone ? RIL_AUDIO_SPEAKERPHONE : RIL_AUDIO_HANDSET;
337
338 result = RIL_SetAudioDevices(hRIL, &info);
339 if (result != S_OK) {
340 wchar_t buffer[200];
341 wsprintf(buffer, L"Could not open RIL, error=0x%x", result);
342 AfxMessageBox(buffer);
343 }
344
345 RIL_Deinitialize(hRIL);
346 }
347
348 #else
349
SetSpeakerMode(bool)350 static void SetSpeakerMode(bool /*speakerphone*/)
351 {
352 }
353
354 #endif // SPEAKERMODE_METHOD
355
356
357 ///////////////////////////////////////////////////////////////////////////////
358
359 // CMobileOpalDlg dialog
360
CMobileOpalDlg(CWnd * pParent)361 CMobileOpalDlg::CMobileOpalDlg(CWnd* pParent /*=NULL*/)
362 : CDialog(CMobileOpalDlg::IDD, pParent)
363 , m_opal(NULL)
364 , m_opalVersion(OPAL_C_API_VERSION)
365 , m_speakerphone(false)
366 , m_hPowerRequirement(NULL)
367 {
368 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
369 }
370
371
~CMobileOpalDlg()372 CMobileOpalDlg::~CMobileOpalDlg()
373 {
374 OpalShutDown(m_opal); // Fail safe shutdown, can handle NULL
375 }
376
377
DoDataExchange(CDataExchange * pDX)378 void CMobileOpalDlg::DoDataExchange(CDataExchange* pDX)
379 {
380 CDialog::DoDataExchange(pDX);
381 DDX_Text(pDX, IDC_ADDRESS, m_callAddress);
382 DDX_Text(pDX, IDC_LOCAL_ADDRESS, m_localAddress);
383 DDX_Control(pDX, IDC_ADDRESS, m_ctrlCallAddress);
384 DDX_Control(pDX, IDC_STATUS, m_ctrlStatus);
385 DDX_Control(pDX, IDC_LOCAL_ADDRESS, m_ctrlLocalStatus);
386 }
387
388
BEGIN_MESSAGE_MAP(CMobileOpalDlg,CDialog)389 BEGIN_MESSAGE_MAP(CMobileOpalDlg, CDialog)
390 ON_WM_SIZE()
391 ON_WM_TIMER()
392 ON_COMMAND(ID_CALL_ANSWER, &CMobileOpalDlg::OnCallAnswer)
393 ON_CBN_EDITCHANGE(IDC_ADDRESS, &CMobileOpalDlg::OnChangedAddress)
394 ON_CBN_SELENDOK(IDC_ADDRESS, &CMobileOpalDlg::OnSelectedAddress)
395 ON_COMMAND(IDM_OPTIONS_GENERAL, &CMobileOpalDlg::OnMenuOptionsGeneral)
396 ON_COMMAND(IDM_OPTIONS_CODECS, &CMobileOpalDlg::OnMenuOptionsCodecs)
397 ON_COMMAND(IDM_OPTIONS_H323, &CMobileOpalDlg::OnMenuOptionsH323)
398 ON_COMMAND(IDM_OPTIONS_SIP, &CMobileOpalDlg::OnMenuOptionsSIP)
399 ON_COMMAND(IDM_EXIT, &CMobileOpalDlg::OnExit)
400 ON_COMMAND(IDM_SPEAKERPHONE, &CMobileOpalDlg::OnSpeakerphone)
401 END_MESSAGE_MAP()
402
403
404 // CMobileOpalDlg message handlers
405
406 BOOL CMobileOpalDlg::OnInitDialog()
407 {
408 CDialog::OnInitDialog();
409
410 // Set the icon for this dialog. The framework does this automatically
411 // when the application's main window is not a dialog
412 SetIcon(m_hIcon, TRUE); // Set big icon
413 SetIcon(m_hIcon, FALSE); // Set small icon
414
415 if (!m_dlgCommandBar.Create(this) || !m_dlgCommandBar.InsertMenuBar(IDR_MAINFRAME)) {
416 TRACE0("Failed to create CommandBar\n");
417 EndDialog(IDCANCEL);
418 return FALSE; // fail to create
419 }
420
421 // Resize to screen width
422 ShowWindow(SW_SHOWMAXIMIZED);
423
424 // Start background check for OPAL messages
425 SetTimer(TimerID, 100, NULL);
426
427 // Recent calls list
428 unsigned index = 1;
429 for (;;) {
430 CString key;
431 key.Format(L"%04u", index++);
432 CString uri = AfxGetApp()->GetProfileString(RecentCallsSection, key);
433 if (uri.IsEmpty())
434 break;
435 m_ctrlCallAddress.AddString(uri);
436 }
437
438 // Speakerphone state
439 m_speakerphone = false;
440 SetSpeakerMode(m_speakerphone);
441
442 // Get interfaces
443 CStringArray interfaces;
444 GetNetworkInterfaces(interfaces, false);
445 for (int i = 0; i < interfaces.GetSize(); ++i) {
446 if (!m_localAddress.IsEmpty())
447 m_localAddress += ", ";
448 m_localAddress += interfaces[i];
449 }
450 UpdateData(false);
451
452 SetCallButton(false);
453
454 return TRUE; // return TRUE unless you set the focus to a control
455 }
456
457
OnSize(UINT,int cx,int cy)458 void CMobileOpalDlg::OnSize(UINT /*nType*/, int cx, int cy)
459 {
460 // Adjust some controls to be full width of screen
461 CRect box;
462 m_ctrlCallAddress.GetWindowRect(&box);
463 m_ctrlCallAddress.SetWindowPos(NULL, 0, 0, cx-box.left*2, box.Height(), SWP_NOMOVE|SWP_NOZORDER);
464 m_ctrlLocalStatus.GetWindowRect(&box);
465 m_ctrlLocalStatus.SetWindowPos(NULL, 0, 0, cx-box.left, box.Height(), SWP_NOMOVE|SWP_NOZORDER);
466 m_ctrlStatus.GetWindowRect(&box);
467 m_ctrlStatus.SetWindowPos(NULL, 0, 0, cx, box.Height(), SWP_NOMOVE|SWP_NOZORDER);
468 }
469
470
InitialiseOPAL()471 void CMobileOpalDlg::InitialiseOPAL()
472 {
473 /////////////////////////////////////////////////////////////////////
474 // Start up and initialise OPAL
475
476 if (m_opal == NULL) {
477 m_opal = OpalInitialise(&m_opalVersion, "pc h323 sip " TRACE_OPTIONS);
478 if (m_opal == NULL) {
479 ErrorBox(IDS_INIT_FAIL);
480 EndDialog(IDCANCEL);
481 return;
482 }
483 }
484
485 OpalMessage command;
486 OpalMessage * response;
487
488 // SIP registrar un-regisration
489 CStringA strAOR = GetOptionStringA(RegistrarAorKey);
490 CStringA strHost = GetOptionStringA(RegistrarHostKey);
491 if (!m_currentAOR.IsEmpty() && (m_currentAOR != strAOR || m_currentHost != strHost)) {
492 // Registration changed, so unregister the previous name
493 memset(&command, 0, sizeof(command));
494 command.m_type = OpalCmdRegistration;
495 command.m_param.m_registrationInfo.m_protocol = "sip";
496 command.m_param.m_registrationInfo.m_identifier = m_currentAOR;
497 command.m_param.m_registrationInfo.m_hostName = m_currentHost;
498 response = OpalSendMessage(m_opal, &command);
499 if (response != NULL && response->m_type == OpalCmdRegistration) {
500 OpalFreeMessage(response);
501
502 UpdateWindow();
503
504 // Wait for unregister to complete.
505 while ((response = OpalGetMessage(m_opal, 30000)) != NULL) {
506 HandleMessage(*response);
507 if (response->m_type == OpalIndRegistration && response->m_param.m_registrationStatus.m_status == OpalRegisterRemoved)
508 break;
509 }
510 }
511 OpalFreeMessage(response);
512 m_currentAOR.Empty();
513 m_currentHost.Empty();
514 }
515
516 /* Calucalte some configuration strings, determine position of a QCIF
517 window so is in bottom left corner, and a preview window for camera
518 in lower right corner, scaled to fit remaining space. */
519 static const unsigned videoWidth = 176;
520 static const unsigned videoHeight = 144;
521 CRect box;
522 GetClientRect(&box);
523
524 CRect commandBox;
525 m_dlgCommandBar.GetWindowRect(&commandBox);
526 box.bottom -= commandBox.Height();
527
528 CStringA strVideoOutputDevice;
529 strVideoOutputDevice.Format("MSWIN STYLE=0x%08X PARENT=0x%08X X=%i Y=%i WIDTH=%u HEIGHT=%u",
530 WS_CHILD|WS_BORDER, GetSafeHwnd(),
531 0, box.Height()-videoHeight,
532 videoWidth, videoHeight);
533
534 unsigned previewWidth = box.Width() - videoWidth - 2;
535 unsigned previewHeight = previewWidth*videoHeight/videoWidth;
536 CStringA strVideoPreviewDevice;
537 strVideoPreviewDevice.Format("MSWIN STYLE=0x%08X PARENT=0x%08X X=%i Y=%i WIDTH=%u HEIGHT=%u",
538 WS_CHILD|WS_BORDER, GetSafeHwnd(),
539 videoWidth+2, box.Height()-previewHeight,
540 previewWidth, previewHeight);
541
542 CStringA strMediaOptions = GetOptionStringA(MediaOptionsKey, DefaultMediaOptions);
543 strMediaOptions.AppendFormat("Video:Max Bit Rate=128000\n"
544 "Video:Target Bit Rate=128000\n"
545 "Video:Frame Time=9000\n" // 10 frames/second
546 "Video:Frame Width=%u\n"
547 "Video:Frame Height=%u\n"
548 "Video:Max Rx Frame Width=%u\n"
549 "Video:Max Rx Frame Height=%u\n",
550 videoWidth, videoHeight,
551 videoWidth, videoHeight);
552
553 CStringA strMediaOrder = GetOptionStringA(MediaOrderKey, DefaultMediaOrder);
554 CStringA strMediaMask = GetOptionStringA(MediaMaskKey, DefaultMediaMask);
555 CStringA strStunServer = GetOptionStringA(STUNServerKey);
556
557 // General options
558 memset(&command, 0, sizeof(command));
559 command.m_type = OpalCmdSetGeneralParameters;
560
561 command.m_param.m_general.m_stunServer = strStunServer;
562 command.m_param.m_general.m_audioPlayerDevice = "Audio Output";
563 command.m_param.m_general.m_audioRecordDevice = "Audio Input";
564 command.m_param.m_general.m_videoInputDevice = "CAM1:";
565 command.m_param.m_general.m_videoOutputDevice = strVideoOutputDevice;
566 command.m_param.m_general.m_videoPreviewDevice = strVideoPreviewDevice;
567 command.m_param.m_general.m_mediaOrder = strMediaOrder;
568 command.m_param.m_general.m_mediaMask = strMediaMask;
569 command.m_param.m_general.m_mediaOptions = strMediaOptions;
570 command.m_param.m_general.m_autoTxMedia = GetOptionInt(AutoStartTxVideoKey, true) != 0 ? "audio video" : "audio";
571 command.m_param.m_general.m_rtpMaxPayloadSize = 1400;
572
573 if ((response = OpalSendMessage(m_opal, &command)) == NULL || response->m_type == OpalIndCommandError)
574 ErrorBox(IDS_CONFIGURATION_FAIL, response);
575 OpalFreeMessage(response);
576
577 // Options across all protocols
578 memset(&command, 0, sizeof(command));
579 command.m_type = OpalCmdSetProtocolParameters;
580
581 CStringA strUserName = GetOptionStringA(UserNameKey);
582 command.m_param.m_protocol.m_userName = strUserName;
583
584 CStringA strDisplayName = GetOptionStringA(UserNameKey);
585 command.m_param.m_protocol.m_displayName = strDisplayName;
586
587 CStringA interfaceAddress = GetOptionStringA(InterfaceAddressKey, L"*");
588 command.m_param.m_protocol.m_interfaceAddresses = interfaceAddress;
589
590 if ((response = OpalSendMessage(m_opal, &command)) == NULL || response->m_type == OpalIndCommandError)
591 ErrorBox(IDS_LISTEN_FAIL, response);
592 OpalFreeMessage(response);
593
594 // H.323 gatekeeper registration
595 memset(&command, 0, sizeof(command));
596 command.m_type = OpalCmdRegistration;
597
598 UINT gkType = GetOptionInt(GkTypeKey);
599 if (gkType > 0) {
600 command.m_param.m_registrationInfo.m_protocol = "h323";
601
602 CStringA strAliasName = GetOptionStringA(GkAliasKey);
603 command.m_param.m_registrationInfo.m_identifier = strAliasName;
604
605 CStringA strGkId = GetOptionStringA(GkIdKey);
606 command.m_param.m_registrationInfo.m_adminEntity = strGkId;
607
608 CStringA strGkHost = GetOptionStringA(GkHostKey);
609 command.m_param.m_registrationInfo.m_hostName = strGkHost;
610
611 CStringA strGkAuthUser = GetOptionStringA(GkAuthUserKey);
612 command.m_param.m_registrationInfo.m_authUserName = strGkAuthUser;
613
614 CStringA strGkPassword = GetOptionStringA(GkPasswordKey);
615 command.m_param.m_registrationInfo.m_password = strGkPassword;
616
617 SetStatusText(IDS_REGISTERING);
618 if ((response = OpalSendMessage(m_opal, &command)) == NULL || response->m_type == OpalIndCommandError)
619 ErrorBox(IDS_REGISTRATION_FAIL, response);
620 OpalFreeMessage(response);
621 }
622
623 // SIP registrar registration
624 if (strAOR.IsEmpty())
625 SetStatusText(IDS_READY);
626 else {
627 memset(&command, 0, sizeof(command));
628 command.m_type = OpalCmdRegistration;
629
630 command.m_param.m_registrationInfo.m_protocol = "sip";
631
632 command.m_param.m_registrationInfo.m_identifier = strAOR;
633 command.m_param.m_registrationInfo.m_hostName = strHost;
634
635 CStringA strAuthUser = GetOptionStringA(RegistrarUserKey);
636 command.m_param.m_registrationInfo.m_authUserName = strAuthUser;
637
638 CStringA strPassword = GetOptionStringA(RegistrarPassKey);
639 command.m_param.m_registrationInfo.m_password = strPassword;
640
641 CStringA strRealm = GetOptionStringA(RegistrarRealmKey);
642 command.m_param.m_registrationInfo.m_adminEntity = strRealm;
643
644 command.m_param.m_registrationInfo.m_timeToLive = 300;
645
646 SetStatusText(IDS_REGISTERING);
647 if ((response = OpalSendMessage(m_opal, &command)) != NULL && response->m_type != OpalIndCommandError) {
648 m_currentAOR = strAOR;
649 m_currentHost = strHost;
650 }
651 else {
652 ErrorBox(IDS_REGISTRATION_FAIL, response);
653 SetStatusText(IDS_READY);
654 }
655 OpalFreeMessage(response);
656 }
657
658 PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE);
659 }
660
661
ErrorBox(UINT ids,const OpalMessage * response)662 void CMobileOpalDlg::ErrorBox(UINT ids, const OpalMessage * response)
663 {
664 CString text;
665 if (response != NULL && response->m_param.m_commandError != NULL || *response->m_param.m_commandError != '\0')
666 text = response->m_param.m_commandError;
667 else {
668 if (ids != 0)
669 text.LoadString(ids);
670 else
671 text = "Error!";
672 }
673
674 MessageBox(text, NULL, MB_OK|MB_ICONEXCLAMATION);
675 }
676
677
SetStatusText(UINT ids,const char * str)678 void CMobileOpalDlg::SetStatusText(UINT ids, const char * str)
679 {
680 CString text;
681 if (str != NULL && str[0] != '\0') {
682 if (isdigit(*str)) {
683 char * colon;
684 unsigned code = strtoul(str, &colon, 10);
685 if (*colon == ':') {
686 str = colon+1;
687 while (isspace(*str))
688 str++;
689 text.LoadString(ids+IDS_CUSTOM_MESSAGES);
690 }
691 }
692
693 if (text.IsEmpty())
694 text = str;
695 }
696 else {
697 if (ids == 0)
698 return;
699 text.LoadString(ids);
700 }
701
702 m_ctrlStatus.SetWindowText(text);
703 m_ctrlStatus.UpdateWindow();
704 }
705
706
SetCallButton(bool enabled,UINT strId)707 void CMobileOpalDlg::SetCallButton(bool enabled, UINT strId)
708 {
709 TBBUTTONINFO tbi;
710 memset (&tbi, 0, sizeof (tbi));
711 tbi.cbSize = sizeof (tbi);
712 tbi.dwMask = TBIF_STATE;
713 if (!::SendMessageW(m_dlgCommandBar.m_hCommandBar, TB_GETBUTTONINFO, ID_CALL_ANSWER, (LPARAM)&tbi))
714 return;
715
716 if (enabled)
717 tbi.fsState |= TBSTATE_ENABLED;
718 else
719 tbi.fsState &= ~TBSTATE_ENABLED;
720
721 CString text;
722 if (strId != 0 && text.LoadString(strId)) {
723 tbi.dwMask |= TBIF_TEXT;
724 tbi.pszText = (LPWSTR)(const TCHAR *)text;
725 }
726 ::SendMessageW(m_dlgCommandBar.m_hCommandBar, TB_SETBUTTONINFO, ID_CALL_ANSWER, (LPARAM)&tbi);
727 }
728
729
AddRecentCall(const CString & uri)730 void CMobileOpalDlg::AddRecentCall(const CString & uri)
731 {
732 int index = m_ctrlCallAddress.FindStringExact(-1, uri);
733 if (index == 0)
734 return;
735
736 if (index > 0)
737 m_ctrlCallAddress.DeleteString(index);
738
739 m_ctrlCallAddress.InsertString(0, uri);
740
741 index = 0;
742 while (index < m_ctrlCallAddress.GetCount()) {
743 CString str;
744 m_ctrlCallAddress.GetLBText(index, str);
745 CString key;
746 key.Format(L"%04u", ++index);
747 AfxGetApp()->WriteProfileString(RecentCallsSection, key, str);
748 }
749 }
750
751
EnableFullPower()752 void CMobileOpalDlg::EnableFullPower()
753 {
754 m_hPowerRequirement = SetPowerRequirement(_T("WAV1:"), D0, POWER_FORCE|POWER_NAME, NULL, 0);
755 if (m_hPowerRequirement == NULL)
756 MessageBox(_T("Could not set power mode!"));
757 SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
758 }
759
760
OnTimer(UINT_PTR nIDEvent)761 void CMobileOpalDlg::OnTimer(UINT_PTR nIDEvent)
762 {
763 if (m_opal == NULL)
764 InitialiseOPAL();
765
766 if (nIDEvent == TimerID && m_opal != NULL) {
767 OpalMessage * message = OpalGetMessage(m_opal, 0);
768 if (message != NULL) {
769 HandleMessage(*message);
770 OpalFreeMessage(message);
771 }
772 }
773
774 CDialog::OnTimer(nIDEvent);
775 }
776
777
HandleMessage(OpalMessage & message)778 void CMobileOpalDlg::HandleMessage(OpalMessage & message)
779 {
780 switch (message.m_type) {
781 case OpalIndRegistration :
782 switch (message.m_param.m_registrationStatus.m_status) {
783 case OpalRegisterSuccessful :
784 case OpalRegisterRestored :
785 SetStatusText(IDS_REGISTERED);
786 break;
787
788 case OpalRegisterRemoved :
789 SetStatusText(IDS_UNREGISTERED, message.m_param.m_registrationStatus.m_error);
790 break;
791
792 case OpalRegisterRetrying :
793 SetStatusText(IDS_REGISTERING);
794 break;
795
796 case OpalRegisterFailed :
797 SetStatusText(0, message.m_param.m_registrationStatus.m_error);
798 }
799 break;
800
801 case OpalIndMessageWaiting :
802 if (message.m_param.m_messageWaiting.m_type != NULL && *message.m_param.m_messageWaiting.m_type != '\0') {
803 CStringA msg;
804 msg.Format(IDS_MESSAGE_WAITING,
805 message.m_param.m_messageWaiting.m_type,
806 message.m_param.m_messageWaiting.m_party);
807 SetStatusText(0, msg);
808 }
809 break;
810
811 case OpalIndIncomingCall :
812 if (m_incomingCallToken.IsEmpty() && m_currentCallToken.IsEmpty()) {
813 m_incomingCallToken = message.m_param.m_incomingCall.m_callToken;
814
815 CString text;
816 text.LoadString(IDS_INCOMING_CALL);
817 text += "\r\n";
818 if (*message.m_param.m_incomingCall.m_remoteDisplayName != '\0')
819 text += message.m_param.m_incomingCall.m_remoteDisplayName;
820 else if (*message.m_param.m_incomingCall.m_remoteAddress != '\0')
821 text += message.m_param.m_incomingCall.m_remoteAddress;
822 m_ctrlStatus.SetWindowText(text);
823 m_ctrlStatus.UpdateWindow();
824
825 SetCallButton(true, IDS_ANSWER);
826 m_ctrlCallAddress.EnableWindow(false);
827 ShowWindow(true);
828 BringWindowToTop();
829 EnableFullPower();
830 }
831 else {
832 OpalMessage command;
833 memset(&command, 0, sizeof(command));
834 command.m_type = OpalCmdClearCall;
835 command.m_param.m_clearCall.m_callToken = message.m_param.m_incomingCall.m_callToken;
836 command.m_param.m_clearCall.m_reason = OpalCallEndedByAnswerDenied;
837 OpalMessage * response = OpalSendMessage(m_opal, &command);
838 if (response != NULL)
839 OpalFreeMessage(response);
840 SetStatusText(IDS_BUSY);
841 }
842 break;
843
844 case OpalIndAlerting :
845 SetStatusText(IDS_RINGING);
846 break;
847
848 case OpalIndEstablished :
849 SetSpeakerMode(m_speakerphone);
850 SetStatusText(IDS_ESTABLISHED);
851 break;
852
853 case OpalIndUserInput :
854 SetStatusText(0, message.m_param.m_userInput.m_userInput);
855 break;
856
857 case OpalIndCallCleared :
858 if (m_currentCallToken == message.m_param.m_callCleared.m_callToken ||
859 m_incomingCallToken == message.m_param.m_callCleared.m_callToken) {
860 m_incomingCallToken.Empty();
861 m_currentCallToken.Empty();
862
863 SetCallButton(true, IDS_CALL);
864 m_ctrlCallAddress.EnableWindow(true);
865
866 SetStatusText(IDS_READY, message.m_param.m_callCleared.m_reason);
867
868 if (m_hPowerRequirement != NULL) {
869 ReleasePowerRequirement(m_hPowerRequirement);
870 m_hPowerRequirement = NULL;
871 }
872 PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE);
873 }
874 }
875 }
876
OnOK()877 void CMobileOpalDlg::OnOK()
878 {
879 #if WIN32_PLATFORM_WFSP
880 // For Smartphone this is the centre button
881 OnCallAnswer();
882 #else
883 // For Pocket PC this is the OK button in the top line
884 OnCancel();
885 #endif
886 }
887
888
OnCancel()889 void CMobileOpalDlg::OnCancel()
890 {
891 CString msg(MAKEINTRESOURCE(IDS_ASK_EXIT));
892 if (MessageBox(msg, NULL, MB_YESNO|MB_ICONQUESTION) == IDYES)
893 OnExit();
894 }
895
896
OnExit()897 void CMobileOpalDlg::OnExit()
898 {
899 if (m_opal != NULL) {
900 KillTimer(TimerID);
901 m_ctrlCallAddress.EnableWindow(false);
902 SetStatusText(IDS_SHUTTING_DOWN);
903 UpdateWindow();
904
905 OpalShutDown(m_opal);
906 m_opal = NULL;
907 SetStatusText(0, "Shut down completed.");
908 Sleep(2000);
909 }
910
911 CDialog::OnCancel();
912 }
913
914
OnCallAnswer()915 void CMobileOpalDlg::OnCallAnswer()
916 {
917 UpdateData();
918
919 OpalMessage * response = NULL;
920 OpalMessage command;
921 memset(&command, 0, sizeof(command));
922
923 if (!m_incomingCallToken.IsEmpty()) {
924 SetStatusText(IDS_ANSWERING);
925 SetCallButton(true, IDS_HANGUP);
926 command.m_type = OpalCmdAnswerCall;
927 command.m_param.m_callToken = m_incomingCallToken;
928 response = OpalSendMessage(m_opal, &command);
929 }
930 else if (!m_currentCallToken.IsEmpty()) {
931 SetStatusText(IDS_HANGINGUP);
932 SetCallButton(false, IDS_HANGUP);
933 command.m_type = OpalCmdClearCall;
934 command.m_param.m_callCleared.m_callToken = m_currentCallToken;
935 response = OpalSendMessage(m_opal, &command);
936 }
937 else if (!m_callAddress.IsEmpty()) {
938 SetStatusText(IDS_CALLING);
939 SetCallButton(true, IDS_HANGUP);
940 CStringA utfAddress((const TCHAR *)m_callAddress);
941 command.m_type = OpalCmdSetUpCall;
942 command.m_param.m_callSetUp.m_partyB = utfAddress;
943 response = OpalSendMessage(m_opal, &command);
944 }
945
946 if (response == NULL)
947 ErrorBox(IDS_CALL_START_FAIL);
948 else {
949 if (response->m_type == OpalIndCommandError) {
950 ErrorBox(IDS_CALL_START_FAIL, response);
951 SetCallButton(true, IDS_CALL);
952 }
953 else if (command.m_type == OpalCmdSetUpCall) {
954 m_currentCallToken = response->m_param.m_callSetUp.m_callToken;
955 AddRecentCall(m_callAddress);
956 EnableFullPower();
957 }
958 else if (command.m_type == OpalCmdAnswerCall) {
959 m_currentCallToken = m_incomingCallToken;
960 m_incomingCallToken.Empty();
961 }
962
963 OpalFreeMessage(response);
964 }
965 }
966
967
OnChangedAddress()968 void CMobileOpalDlg::OnChangedAddress()
969 {
970 SetCallButton(m_ctrlCallAddress.GetWindowTextLength() > 0);
971 }
972
973
OnSelectedAddress()974 void CMobileOpalDlg::OnSelectedAddress()
975 {
976 SetCallButton(true);
977 }
978
979
OnMenuOptionsGeneral()980 void CMobileOpalDlg::OnMenuOptionsGeneral()
981 {
982 COptionsGeneral dlg;
983 dlg.m_strUsername = GetOptionString(UserNameKey);
984 dlg.m_strDisplayName = GetOptionString(DisplayNameKey);
985 dlg.m_strStunServer = GetOptionString(STUNServerKey);
986 dlg.m_interfaceAddress = GetOptionString(InterfaceAddressKey, L"*");
987
988 if (dlg.DoModal() == IDOK) {
989 SetOptionString(UserNameKey, dlg.m_strUsername);
990 SetOptionString(DisplayNameKey, dlg.m_strDisplayName);
991 SetOptionString(STUNServerKey, dlg.m_strStunServer);
992 SetOptionString(InterfaceAddressKey, dlg.m_interfaceAddress);
993 InitialiseOPAL();
994 }
995 }
996
997
OnMenuOptionsCodecs()998 void CMobileOpalDlg::OnMenuOptionsCodecs()
999 {
1000 COptionsCodecs dlg;
1001 dlg.m_AutoStartTxVideo = GetOptionInt(AutoStartTxVideoKey, true) != 0;
1002 dlg.m_MediaOrder = GetOptionString(MediaOrderKey, DefaultMediaOrder);
1003 dlg.m_MediaMask = GetOptionString(MediaMaskKey, DefaultMediaMask);
1004 dlg.m_MediaOptions = GetOptionString(MediaOptionsKey, DefaultMediaOptions);
1005
1006 OpalMessage command;
1007 OpalMessage * response;
1008 memset(&command, 0, sizeof(command));
1009 command.m_type = OpalCmdSetGeneralParameters;
1010 if ((response = OpalSendMessage(m_opal, &command)) != NULL && response->m_type != OpalIndCommandError)
1011 dlg.m_AllMediaOptions = CString(response->m_param.m_general.m_mediaOptions);
1012 OpalFreeMessage(response);
1013
1014 if (dlg.DoModal() == IDOK) {
1015 SetOptionInt(AutoStartTxVideoKey, dlg.m_AutoStartTxVideo);
1016 SetOptionString(MediaOrderKey, dlg.m_MediaOrder);
1017 SetOptionString(MediaMaskKey, dlg.m_MediaMask);
1018 SetOptionString(MediaOptionsKey, dlg.m_MediaOptions);
1019 InitialiseOPAL();
1020 }
1021 }
1022
1023
OnMenuOptionsH323()1024 void CMobileOpalDlg::OnMenuOptionsH323()
1025 {
1026 COptionsH323 dlg;
1027 dlg.m_uiGatekeeperType = GetOptionInt(GkTypeKey);
1028 dlg.m_strGkId = GetOptionString(GkIdKey);
1029 dlg.m_strGkHost = GetOptionString(GkHostKey);
1030 dlg.m_strAlias = GetOptionString(GkAliasKey);
1031 dlg.m_strAuthUser = GetOptionString(GkAuthUserKey);
1032 dlg.m_strPassword = GetOptionString(GkPasswordKey);
1033 if (dlg.DoModal() == IDOK) {
1034 SetOptionInt(GkTypeKey, dlg.m_uiGatekeeperType);
1035 SetOptionString(GkIdKey, dlg.m_strGkId);
1036 SetOptionString(GkHostKey, dlg.m_strGkHost);
1037 SetOptionString(GkAliasKey, dlg.m_strAlias);
1038 SetOptionString(GkAuthUserKey, dlg.m_strAuthUser);
1039 SetOptionString(GkPasswordKey, dlg.m_strPassword);
1040 InitialiseOPAL();
1041 }
1042 }
1043
1044
OnMenuOptionsSIP()1045 void CMobileOpalDlg::OnMenuOptionsSIP()
1046 {
1047 COptionsSIP dlg;
1048 dlg.m_strAddressOfRecord = GetOptionString(RegistrarAorKey);
1049 dlg.m_strHostName = GetOptionString(RegistrarHostKey);
1050 dlg.m_strAuthUser = GetOptionString(RegistrarUserKey);
1051 dlg.m_strPassword = GetOptionString(RegistrarPassKey);
1052 dlg.m_strRealm = GetOptionString(RegistrarRealmKey);
1053 if (dlg.DoModal() == IDOK) {
1054 SetOptionString(RegistrarAorKey, dlg.m_strAddressOfRecord);
1055 SetOptionString(RegistrarHostKey, dlg.m_strHostName);
1056 SetOptionString(RegistrarUserKey, dlg.m_strAuthUser);
1057 SetOptionString(RegistrarPassKey, dlg.m_strPassword);
1058 SetOptionString(RegistrarRealmKey, dlg.m_strRealm);
1059 InitialiseOPAL();
1060 }
1061 }
1062
1063
OnSpeakerphone()1064 void CMobileOpalDlg::OnSpeakerphone()
1065 {
1066 m_speakerphone = !m_speakerphone;
1067 SetSpeakerMode(m_speakerphone);
1068
1069 HMENU hMenu = (HMENU)::SendMessageW(m_dlgCommandBar.m_hCommandBar, SHCMBM_GETSUBMENU, 0, IDS_OPTIONS);
1070 CheckMenuItem(hMenu, IDM_SPEAKERPHONE, m_speakerphone ? MF_CHECKED : MF_UNCHECKED);
1071 }
1072