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