Fixed deadlocks in OpenPhone Timer/GUI interaction.
[opal/cbnco.git] / samples / openphone / main.cxx
blobcc24acabe1e41f45d34a8e8eb8a28b31eb937a60
1 /*
2 * main.cpp
4 * An OPAL GUI phone application.
6 * Open Phone Abstraction Library (OPAL)
7 * Formally known as the Open H323 project.
8 *
9 * Copyright (c) 2004 Post Increment
11 * The contents of this file are subject to the Mozilla Public License
12 * Version 1.0 (the "License"); you may not use this file except in
13 * compliance with the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
16 * Software distributed under the License is distributed on an "AS IS"
17 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18 * the License for the specific language governing rights and limitations
19 * under the License.
21 * The Original Code is Open Phone client.
23 * The Initial Developer of the Original Code is Post Increment
25 * Contributor(s):
27 * $Log$
28 * Revision 1.19 2007/06/06 09:08:56 rjongbloed
29 * Fixed deadlocks in OpenPhone Timer/GUI interaction.
31 * Revision 1.18 2007/05/20 08:16:12 rjongbloed
32 * Added various handlers to manage subscriptions for presence, message
33 * waiting indications, registrations, state publishing,
34 * message conversations, ...
36 * Revision 1.17 2007/05/10 01:03:54 rjongbloed
37 * Updated build for wxWidgets 2.8.x
39 * Revision 1.16 2007/04/03 07:59:13 rjongbloed
40 * Warning: API change to PCSS callbacks:
41 * changed return on OnShowIncoming to BOOL, now agrees with
42 * documentation and allows UI to abort calls early.
43 * added BOOL to AcceptIncomingConnection indicating the
44 * supplied token is invalid.
45 * removed redundent OnGetDestination() function, was never required.
47 * Revision 1.15 2006/11/19 06:06:01 rjongbloed
48 * Added override for dialing on a LID to use unique speed dial code immediately.
50 * Revision 1.14 2006/11/12 03:39:17 rjongbloed
51 * Fixed setting and saving of LID country code from Options dialog.
53 * Revision 1.13 2006/10/02 13:30:51 rjongbloed
54 * Added LID plug ins
56 * Revision 1.12 2006/09/16 04:20:36 rjongbloed
57 * Fixed crash when entering opetions dialog.
58 * Added recent calls list to Call dialog.
59 * Added "no trace" version.
61 * Revision 1.11 2006/09/07 10:09:24 rjongbloed
62 * Linux/GNU compiler compatibility
64 * Revision 1.10 2006/08/29 08:54:36 rjongbloed
65 * Added VU meters
67 * Revision 1.9 2006/08/17 23:09:03 rjongbloed
68 * Added volume controls
70 * Revision 1.8 2006/08/15 12:10:01 rjongbloed
71 * Added local interfaces to config dialog
73 * Revision 1.7 2006/08/14 22:39:27 rjongbloed
74 * Added aslias to config dialog
76 * Revision 1.6 2006/08/13 08:33:36 rjongbloed
77 * Completed bandwidth configuration from options dialog.
79 * Revision 1.5 2006/08/13 04:41:39 rjongbloed
80 * Fixed saving of ring device name
82 * Revision 1.4 2006/07/31 10:57:52 rjongbloed
83 * Added play of WAV file on incoming calls.
85 * Revision 1.3 2006/07/31 08:05:24 rjongbloed
86 * Fixed unix version of icons.
87 * Fixed some GNU compiler compatibility issues.
89 * Revision 1.2 2006/07/21 23:41:28 dereksmithies
90 * Move main.cpp contents to main.cxx. This fixes many issues under linux.
92 * Revision 1.37 2006/07/19 10:41:51 dereksmithies
93 * First steps towards having a unix compiled openphone.
95 * Revision 1.36 2006/04/30 10:36:24 rjongbloed
96 * Added icons to speed dial list.
98 * Revision 1.35 2006/04/09 12:15:30 rjongbloed
99 * Added extra trace log to dump all known media formats and their options.
101 * Revision 1.34 2005/12/11 19:14:21 dsandras
102 * Added support for setting a different user name and authentication user name
103 * as required by some providers like digisip.
105 * Revision 1.33 2005/08/31 13:21:20 rjongbloed
106 * Moved some video options to be in the options list from OpalMediaFormat
107 * Added selection of video grabber preview window.
109 * Revision 1.32 2005/08/24 10:43:51 rjongbloed
110 * Changed create video functions yet again so can return pointers that are not to be deleted.
112 * Revision 1.31 2005/08/24 10:21:36 rjongbloed
113 * Added function to create video output windows, can now get correct titles.
115 * Revision 1.30 2005/08/10 08:07:44 rjongbloed
116 * Upgraded to support wxWidgets 2.6
117 * Also improved build so uses WXDIR environment variable
119 * Revision 1.29 2005/07/09 07:05:16 rjongbloed
120 * Changed so resources are included in compile and not separate file at run time.
121 * General code clean ups.
123 * Revision 1.28 2005/06/02 13:21:49 rjongbloed
124 * Save and restore media format options to registry.
125 * Added check for valid value for media format option in dialog.
127 * Revision 1.27 2005/02/21 12:19:49 rjongbloed
128 * Added new "options list" to the OpalMediaFormat class.
130 * Revision 1.26 2004/10/06 13:08:19 rjongbloed
131 * Implemented partial support for LIDs
133 * Revision 1.25 2004/10/03 14:16:34 rjongbloed
134 * Added panels for calling, answering and in call phases.
136 * Revision 1.24 2004/09/29 12:47:39 rjongbloed
137 * Added gatekeeper support
139 * Revision 1.23 2004/09/29 12:02:40 rjongbloed
140 * Added popup menu to edit Speed DIals
142 * Revision 1.22 2004/09/28 23:00:17 rjongbloed
143 * Added ability to add and edit Speed DIals
145 * Revision 1.21 2004/08/22 12:27:45 rjongbloed
146 * More work on SIP registration, time to live refresh and deregistration on exit.
148 * Revision 1.20 2004/08/14 07:56:30 rjongbloed
149 * Major revision to utilise the PSafeCollection classes for the connections and calls.
151 * Revision 1.19 2004/07/17 08:21:24 rjongbloed
152 * Added ability to manipulate codec lists
154 * Revision 1.18 2004/07/14 13:17:42 rjongbloed
155 * Added saving of the width of columns in the speed dial list.
156 * Fixed router display in options dialog so is empty if IP address invalid.
158 * Revision 1.17 2004/07/11 12:42:11 rjongbloed
159 * Added function on endpoints to get the list of all media formats any
160 * connection the endpoint may create can support.
162 * Revision 1.16 2004/07/04 12:53:09 rjongbloed
163 * Added support for route editing.
165 * Revision 1.15 2004/06/05 14:37:03 rjongbloed
166 * More implemntation of options dialog.
168 * Revision 1.14 2004/05/25 12:55:52 rjongbloed
169 * Added all silence suppression modes to Options dialog.
171 * Revision 1.13 2004/05/24 13:44:03 rjongbloed
172 * More implementation on OPAL OpenPhone.
174 * Revision 1.12 2004/05/15 12:18:23 rjongbloed
175 * More work on wxWindows based OpenPhone
177 * Revision 1.11 2004/05/12 12:41:38 rjongbloed
178 * More work on wxWindows based OpenPhone
180 * Revision 1.10 2004/05/09 13:24:25 rjongbloed
181 * More work on wxWindows based OpenPhone
183 * Revision 1.9 2004/05/06 13:23:43 rjongbloed
184 * Work on wxWindows based OpenPhone
186 * Revision 1.8 2004/05/01 13:38:05 rjongbloed
187 * Some early implementation of wxWIndows based OPAL GUI client.
191 #ifdef __GNUG__
192 #pragma implementation
193 #pragma interface
194 #endif
196 #include "main.h"
197 #include "version.h"
199 #include <wx/config.h>
200 #include <wx/filesys.h>
201 #include <wx/gdicmn.h> //Required for icons on linux.
202 #include <wx/image.h>
203 #include <wx/listctrl.h>
204 #include <wx/splitter.h>
205 #include <wx/valgen.h>
206 #include <wx/notebook.h>
207 #undef LoadMenu // Bizarre but necessary before the xml code
208 #include <wx/xrc/xmlres.h>
210 #include <opal/transcoders.h>
211 #include <opal/ivr.h>
212 #include <lids/lidep.h>
213 #include <ptclib/pstun.h>
216 #if defined(__WXGTK__) || \
217 defined(__WXMOTIF__) || \
218 defined(__WXX11__) || \
219 defined(__WXMAC__) || \
220 defined(__WXMGL__) || \
221 defined(__WXCOCOA__)
222 #include "openphone.xpm"
223 #include "h323phone.xpm"
224 #include "sipphone.xpm"
225 #include "otherphone.xpm"
226 #include "smallphone.xpm"
227 #endif
230 extern void InitXmlResource(); // From resource.cpp whichis compiled openphone.xrc
232 // Definitions of the configuration file section and key names
234 #define DEF_FIELD(name) static const char name##Key[] = #name
236 static const char AppearanceGroup[] = "/Appearance";
237 DEF_FIELD(MainFrameX);
238 DEF_FIELD(MainFrameY);
239 DEF_FIELD(MainFrameWidth);
240 DEF_FIELD(MainFrameHeight);
241 DEF_FIELD(SashPosition);
242 DEF_FIELD(ActiveView);
244 static const char GeneralGroup[] = "/General";
245 DEF_FIELD(Username);
246 DEF_FIELD(DisplayName);
247 DEF_FIELD(RingSoundDeviceName);
248 DEF_FIELD(RingSoundFileName);
249 DEF_FIELD(AutoAnswer);
250 DEF_FIELD(IVRScript);
251 DEF_FIELD(SpeakerVolume);
252 DEF_FIELD(MicrophoneVolume);
254 static const char NetworkingGroup[] = "/Networking";
255 DEF_FIELD(Bandwidth);
256 DEF_FIELD(TCPPortBase);
257 DEF_FIELD(TCPPortMax);
258 DEF_FIELD(UDPPortBase);
259 DEF_FIELD(UDPPortMax);
260 DEF_FIELD(RTPPortBase);
261 DEF_FIELD(RTPPortMax);
262 DEF_FIELD(RTPTOS);
263 DEF_FIELD(STUNServer);
264 DEF_FIELD(NATRouter);
266 static const char LocalInterfacesGroup[] = "/Networking/Interfaces";
268 static const char AudioGroup[] = "/Audio";
269 DEF_FIELD(SoundPlayer);
270 DEF_FIELD(SoundRecorder);
271 DEF_FIELD(SoundBuffers);
272 DEF_FIELD(LineInterfaceDevice);
273 DEF_FIELD(AEC);
274 DEF_FIELD(Country);
275 DEF_FIELD(MinJitter);
276 DEF_FIELD(MaxJitter);
277 DEF_FIELD(SilenceSuppression);
278 DEF_FIELD(SilenceThreshold);
279 DEF_FIELD(SignalDeadband);
280 DEF_FIELD(SilenceDeadband);
282 static const char VideoGroup[] = "/Video";
283 DEF_FIELD(VideoGrabber);
284 DEF_FIELD(VideoGrabFormat);
285 DEF_FIELD(VideoGrabSource);
286 DEF_FIELD(VideoGrabFrameRate);
287 DEF_FIELD(VideoGrabPreview);
288 DEF_FIELD(VideoFlipLocal);
289 DEF_FIELD(VideoAutoTransmit);
290 DEF_FIELD(VideoAutoReceive);
291 DEF_FIELD(VideoFlipRemote);
293 static const char CodecsGroup[] = "/Codecs";
294 static const char CodecNameKey[] = "Name";
296 static const char H323Group[] = "/H.323";
297 DEF_FIELD(GatekeeperMode);
298 DEF_FIELD(GatekeeperAddress);
299 DEF_FIELD(GatekeeperIdentifier);
300 DEF_FIELD(GatekeeperTTL);
301 DEF_FIELD(GatekeeperLogin);
302 DEF_FIELD(GatekeeperPassword);
303 DEF_FIELD(DTMFSendMode);
304 DEF_FIELD(CallIntrusionProtectionLevel);
305 DEF_FIELD(DisableFastStart);
306 DEF_FIELD(DisableH245Tunneling);
307 DEF_FIELD(DisableH245inSETUP);
309 static const char H323AliasesGroup[] = "/H.323/Aliases";
311 static const char SIPGroup[] = "/SIP";
312 DEF_FIELD(SIPProxyUsed);
313 DEF_FIELD(SIPProxy);
314 DEF_FIELD(SIPProxyUsername);
315 DEF_FIELD(SIPProxyPassword);
316 DEF_FIELD(RegistrarUsed);
317 DEF_FIELD(RegistrarName);
318 DEF_FIELD(RegistrarUsername);
319 DEF_FIELD(RegistrarPassword);
320 DEF_FIELD(RegistrarTimeToLive);
322 static const char RoutingGroup[] = "/Routes";
324 #if PTRACING
325 static const char TracingGroup[] = "/Tracing";
326 DEF_FIELD(EnableTracing);
327 DEF_FIELD(TraceLevelThreshold);
328 DEF_FIELD(TraceLevelNumber);
329 DEF_FIELD(TraceFileLine);
330 DEF_FIELD(TraceBlocks);
331 DEF_FIELD(TraceDateTime);
332 DEF_FIELD(TraceTimestamp);
333 DEF_FIELD(TraceThreadName);
334 DEF_FIELD(TraceThreadAddress);
335 DEF_FIELD(TraceFileName);
336 DEF_FIELD(TraceOptions);
337 #endif
339 static const char SpeedDialsGroup[] = "/Speed Dials";
340 static const char SpeedDialAddressKey[] = "Address";
341 static const char SpeedDialNumberKey[] = "Number";
342 static const char SpeedDialDescriptionKey[] = "Description";
344 static const char RecentCallsGroup[] = "/Recent Calls";
345 static const size_t MaxSavedRecentCalls = 10;
348 ///////////////////////////////////////////////////////////////////////////////
350 template <class cls> cls * FindWindowByNameAs(wxWindow * window, const char * name)
352 cls * child = dynamic_cast<cls *>(window->FindWindowByName(name));
353 if (child != NULL)
354 return child;
355 PAssertAlways("Cannot cast window object to class");
356 return NULL;
360 ///////////////////////////////////////////////////////////////////////////////
362 class TextCtrlChannel : public PChannel
364 PCLASSINFO(TextCtrlChannel, PChannel)
365 public:
366 TextCtrlChannel(wxTextCtrl * textCtrl = NULL)
367 : m_textCtrl(textCtrl)
370 virtual BOOL Write(
371 const void * buf, /// Pointer to a block of memory to write.
372 PINDEX len /// Number of bytes to write.
374 if (m_textCtrl == NULL)
375 return FALSE;
376 m_textCtrl->WriteText(wxString((const wxChar *)buf, (size_t)len));
377 return TRUE;
380 void SetTextCtrl(
381 wxTextCtrl * textCtrl
382 ) { m_textCtrl = textCtrl; }
384 protected:
385 wxTextCtrl * m_textCtrl;
386 } LogWindow;
390 ///////////////////////////////////////////////////////////////////////////////
392 IMPLEMENT_APP(OpenPhoneApp)
394 OpenPhoneApp::OpenPhoneApp()
395 : PProcess("Equivalence", "OpenPhone",
396 MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
398 wxConfig::Set(new wxConfig((const char *)GetName(), (const char *)GetManufacturer()));
402 void OpenPhoneApp::Main()
404 // Dummy function
408 bool OpenPhoneApp::OnInit()
410 // Create the main frame window
411 MyManager * main = new MyManager();
412 SetTopWindow(main);
413 wxBeginBusyCursor();
414 bool ok = main->Initialise();
415 wxEndBusyCursor();
416 return ok;
420 ///////////////////////////////////////////////////////////////////////////////
422 BEGIN_EVENT_TABLE(MyManager, wxFrame)
423 EVT_CLOSE(MyManager::OnClose)
425 EVT_MENU_OPEN(MyManager::OnAdjustMenus)
427 EVT_MENU(XRCID("MenuQuit"), MyManager::OnMenuQuit)
428 EVT_MENU(XRCID("MenuAbout"), MyManager::OnMenuAbout)
429 EVT_MENU(XRCID("MenuCall"), MyManager::OnMenuCall)
430 EVT_MENU(XRCID("MenuAnswer"), MyManager::OnMenuAnswer)
431 EVT_MENU(XRCID("MenuHangUp"), MyManager::OnMenuHangUp)
432 EVT_MENU(XRCID("NewSpeedDial"), MyManager::OnNewSpeedDial)
433 EVT_MENU(XRCID("ViewLarge"), MyManager::OnViewLarge)
434 EVT_MENU(XRCID("ViewSmall"), MyManager::OnViewSmall)
435 EVT_MENU(XRCID("ViewList"), MyManager::OnViewList)
436 EVT_MENU(XRCID("ViewDetails"), MyManager::OnViewDetails)
437 EVT_MENU(XRCID("EditSpeedDial"),MyManager::OnEditSpeedDial)
438 EVT_MENU(XRCID("MenuOptions"), MyManager::OnOptions)
440 EVT_SPLITTER_SASH_POS_CHANGED(SplitterID, MyManager::OnSashPositioned)
441 EVT_LIST_ITEM_ACTIVATED(SpeedDialsID, MyManager::OnSpeedDialActivated)
442 EVT_LIST_COL_END_DRAG(SpeedDialsID, MyManager::OnSpeedDialColumnResize)
443 EVT_LIST_ITEM_RIGHT_CLICK(SpeedDialsID, MyManager::OnRightClick)
444 END_EVENT_TABLE()
446 MyManager::MyManager()
447 : wxFrame(NULL, -1, wxT("OpenPhone"), wxDefaultPosition, wxSize(640, 480)),
448 m_speedDials(NULL),
449 pcssEP(NULL),
450 potsEP(NULL),
451 #if OPAL_H323
452 h323EP(NULL),
453 #endif
454 #if OPAL_SIP
455 sipEP(NULL),
456 #endif
457 #if P_EXPAT
458 ivrEP(NULL),
459 #endif
460 m_callState(IdleState)
463 // Give it an icon
464 SetIcon(wxICON(AppIcon));
466 // Make an image list containing large icons
467 m_imageListNormal = new wxImageList(32, 32, true);
468 // Order here is important!!
469 m_imageListNormal->Add(wxICON(OtherPhone));
470 m_imageListNormal->Add(wxICON(H323Phone));
471 m_imageListNormal->Add(wxICON(SIPPhone));
473 m_imageListSmall = new wxImageList(16, 16, true);
474 m_imageListSmall->Add(wxICON(SmallPhone));
476 m_RingSoundTimer.SetNotifier(PCREATE_NOTIFIER(OnRingSoundAgain));
480 MyManager::~MyManager()
482 LogWindow.SetTextCtrl(NULL);
484 ClearAllCalls();
486 // Must do this before we destroy the manager or a crash will result
487 if (potsEP != NULL)
488 potsEP->RemoveAllLines();
490 delete m_imageListNormal;
491 delete m_imageListSmall;
495 bool MyManager::Initialise()
497 wxImage::AddHandler(new wxGIFHandler);
498 wxXmlResource::Get()->InitAllHandlers();
499 InitXmlResource();
501 // Make a menubar
502 wxMenuBar * menubar = wxXmlResource::Get()->LoadMenuBar("MenuBar");
503 if (menubar == NULL)
504 return false;
506 SetMenuBar(menubar);
508 wxConfigBase * config = wxConfig::Get();
509 config->SetPath(AppearanceGroup);
511 int x, y = 0;
512 if (config->Read(MainFrameXKey, &x) && config->Read(MainFrameYKey, &y))
513 Move(x, y);
515 int w, h = 0;
516 if (config->Read(MainFrameWidthKey, &w) && config->Read(MainFrameHeightKey, &h))
517 SetSize(w, h);
519 // Make the content of the main window, speed dial and log panes inside a splitter
520 m_splitter = new wxSplitterWindow(this, SplitterID, wxDefaultPosition, wxDefaultSize, wxSP_3D);
522 // Log window - gets informative text
523 m_logWindow = new wxTextCtrl(m_splitter, -1, wxEmptyString,
524 wxDefaultPosition, wxDefaultSize,
525 wxTE_MULTILINE | wxSUNKEN_BORDER);
526 LogWindow.SetTextCtrl(m_logWindow);
527 m_logWindow->SetForegroundColour(wxColour(0,255,0)); // Green
528 m_logWindow->SetBackgroundColour(wxColour(0,0,0)); // Black
530 // Speed dial window - icons for each speed dial
531 int i;
532 if (!config->Read(ActiveViewKey, &i) || i < 0 || i >= e_NumViews)
534 i = e_ViewList;
536 static const char * const ViewMenuNames[e_NumViews] = {
537 "ViewLarge", "ViewSmall", "ViewList", "ViewDetails"
539 menubar->Check(XRCID(ViewMenuNames[i]), true);
540 RecreateSpeedDials((SpeedDialViews)i);
542 // Speed dial panel switches to answer panel on ring
543 m_answerPanel = new AnswerPanel(*this, m_splitter);
544 m_answerPanel->Show(false);
546 // Speed dial panel switches to calling panel on dial
547 m_callingPanel = new CallingPanel(*this, m_splitter);
548 m_callingPanel->Show(false);
550 // Speed dial/Answer/Calling panel switches to "in call" panel on successful call establishment
551 m_inCallPanel = new InCallPanel(*this, m_splitter);
552 m_inCallPanel->Show(false);
554 // Set up sizer to automatically resize the splitter to size of window
555 wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL);
556 sizer->Add(m_splitter, 1, wxGROW, 0);
557 SetSizer(sizer);
559 // Show the frame window
560 Show(TRUE);
562 #if PTRACING
563 ////////////////////////////////////////
564 // Tracing fields
565 config->SetPath(TracingGroup);
566 if (config->Read(EnableTracingKey, &m_enableTracing, false) && m_enableTracing &&
567 config->Read(TraceFileNameKey, &m_traceFileName) && !m_traceFileName.empty()) {
568 int traceLevelThreshold = 3;
569 config->Read(TraceLevelThresholdKey, &traceLevelThreshold);
570 int traceOptions = PTrace::DateAndTime|PTrace::Thread|PTrace::FileAndLine;
571 config->Read(TraceOptionsKey, &traceOptions);
572 PTrace::Initialise(traceLevelThreshold, m_traceFileName, traceOptions);
574 #endif
576 ////////////////////////////////////////
577 // Creating the endpoints
578 #if OPAL_H323
579 h323EP = new MyH323EndPoint(*this);
580 #endif
582 #if OPAL_SIP
583 sipEP = new MySIPEndPoint(*this);
584 #endif
586 #if P_EXPAT
587 ivrEP = new OpalIVREndPoint(*this);
588 #endif
590 potsEP = new OpalPOTSEndPoint(*this);
591 pcssEP = new MyPCSSEndPoint(*this);
593 PwxString str;
594 bool onoff;
595 int value1 = 0, value2 = 0;
597 ////////////////////////////////////////
598 // General fields
599 config->SetPath(GeneralGroup);
600 if (config->Read(UsernameKey, &str) && !str.IsEmpty())
601 SetDefaultUserName(str);
602 if (config->Read(DisplayNameKey, &str) && !str.IsEmpty())
603 SetDefaultDisplayName(str);
605 if (!config->Read(RingSoundDeviceNameKey, &m_RingSoundDeviceName))
606 m_RingSoundDeviceName = PSoundChannel::GetDefaultDevice(PSoundChannel::Player);
607 config->Read(RingSoundFileNameKey, &m_RingSoundFileName);
609 config->Read(AutoAnswerKey, &m_autoAnswer);
610 #if P_EXPAT
611 if (config->Read(IVRScriptKey, &str))
612 ivrEP->SetDefaultVXML(str);
613 #endif
615 ////////////////////////////////////////
616 // Networking fields
617 config->SetPath(NetworkingGroup);
618 if (config->Read(BandwidthKey, &value1))
619 h323EP->SetInitialBandwidth(value1);
620 if (config->Read(TCPPortBaseKey, &value1) && config->Read(TCPPortMaxKey, &value2))
621 SetTCPPorts(value1, value2);
622 if (config->Read(UDPPortBaseKey, &value1) && config->Read(UDPPortMaxKey, &value2))
623 SetUDPPorts(value1, value2);
624 if (config->Read(RTPPortBaseKey, &value1) && config->Read(RTPPortMaxKey, &value2))
625 SetRtpIpPorts(value1, value2);
626 if (config->Read(RTPTOSKey, &value1))
627 SetRtpIpTypeofService(value1);
628 if (config->Read(NATRouterKey, &str))
629 SetTranslationAddress(str);
630 if (config->Read(STUNServerKey, &str) && !str.IsEmpty()) {
631 LogWindow << "STUN server \"" << str << "\" being contacted ..." << endl;
632 LogWindow << "STUN server \"" << str << "\" replies " << SetSTUNServer(str) << endl;
635 config->SetPath(LocalInterfacesGroup);
636 wxString entryName;
637 long entryIndex;
638 if (config->GetFirstEntry(entryName, entryIndex)) {
639 do {
640 wxString localInterface;
641 if (config->Read(entryName, &localInterface) && !localInterface.empty())
642 m_LocalInterfaces.AppendString(localInterface.c_str());
643 } while (config->GetNextEntry(entryName, entryIndex));
646 StartAllListeners();
648 ////////////////////////////////////////
649 // Sound fields
650 config->SetPath(AudioGroup);
651 if (config->Read(SoundPlayerKey, &str))
652 pcssEP->SetSoundChannelPlayDevice(str);
653 if (config->Read(SoundRecorderKey, &str))
654 pcssEP->SetSoundChannelRecordDevice(str);
655 if (config->Read(SoundBuffersKey, &value1))
656 pcssEP->SetSoundChannelBufferDepth(value1);
658 if (config->Read(MinJitterKey, &value1)) {
659 config->Read(MaxJitterKey, &value2, value1);
660 SetAudioJitterDelay(value1, value2);
663 OpalSilenceDetector::Params silenceParams = GetSilenceDetectParams();
664 if (config->Read(SilenceSuppressionKey, &value1) && value1 >= 0 && value1 < OpalSilenceDetector::NumModes)
665 silenceParams.m_mode = (OpalSilenceDetector::Mode)value1;
666 if (config->Read(SilenceThresholdKey, &value1))
667 silenceParams.m_threshold = value1;
668 if (config->Read(SignalDeadbandKey, &value1))
669 silenceParams.m_signalDeadband = value1*8;
670 if (config->Read(SilenceDeadbandKey, &value1))
671 silenceParams.m_silenceDeadband = value1*8;
672 SetSilenceDetectParams(silenceParams);
674 if (config->Read(LineInterfaceDeviceKey, &str) && potsEP->AddDeviceName(str)) {
675 OpalLine * line = potsEP->GetLine("*");
676 if (PAssertNULL(line) != NULL) {
677 if (config->Read(AECKey, &value1) && value1 >= 0 && value1 < OpalLineInterfaceDevice::AECError)
678 line->SetAEC((OpalLineInterfaceDevice::AECLevels)value1);
679 if (config->Read(CountryKey, &str)) {
680 if (!line->GetDevice().SetCountryCodeName(str))
681 LogWindow << "Could not configure Line Interface Device to country \"" << str << '"' << endl;
687 ////////////////////////////////////////
688 // Video fields
689 config->SetPath(VideoGroup);
690 PVideoDevice::OpenArgs videoArgs = GetVideoInputDevice();
691 if (config->Read(VideoGrabberKey, &str))
692 videoArgs.deviceName = (PString)PString(str.c_str());
693 if (config->Read(VideoGrabFormatKey, &value1) && value1 >= 0 && value1 < PVideoDevice::NumVideoFormats)
694 videoArgs.videoFormat = (PVideoDevice::VideoFormat)value1;
695 if (config->Read(VideoGrabSourceKey, &value1))
696 videoArgs.channelNumber = value1;
697 if (config->Read(VideoGrabFrameRateKey, &value1))
698 videoArgs.rate = value1;
699 config->Read(VideoFlipLocalKey, &videoArgs.flip);
700 SetVideoInputDevice(videoArgs);
702 config->Read(VideoGrabPreviewKey, &m_VideoGrabPreview);
703 if (config->Read(VideoAutoTransmitKey, &onoff))
704 SetAutoStartTransmitVideo(onoff);
705 if (config->Read(VideoAutoReceiveKey, &onoff))
706 SetAutoStartReceiveVideo(onoff);
708 videoArgs = GetVideoOutputDevice();
709 config->Read(VideoFlipRemoteKey, &videoArgs.flip);
710 SetVideoOutputDevice(videoArgs);
712 ////////////////////////////////////////
713 // Codec fields
714 InitMediaInfo(pcssEP->GetPrefixName(), pcssEP->GetMediaFormats());
715 InitMediaInfo(potsEP->GetPrefixName(), potsEP->GetMediaFormats());
716 #if P_EXPAT
717 InitMediaInfo(ivrEP->GetPrefixName(), ivrEP->GetMediaFormats());
718 #endif
720 OpalMediaFormatList mediaFormats;
721 mediaFormats += pcssEP->GetMediaFormats();
722 mediaFormats += potsEP->GetMediaFormats();
723 #if P_EXPAT
724 mediaFormats += ivrEP->GetMediaFormats();
725 #endif
726 InitMediaInfo("sw", OpalTranscoder::GetPossibleFormats(mediaFormats));
728 config->SetPath(CodecsGroup);
729 int codecIndex = 0;
730 for (;;) {
731 wxString groupName;
732 groupName.sprintf("%04u", codecIndex);
733 if (!config->HasGroup(groupName))
734 break;
736 config->SetPath(groupName);
737 PwxString codecName;
738 if (config->Read(CodecNameKey, &codecName) && !codecName.empty()) {
739 for (MyMediaList::iterator mm = m_mediaInfo.begin(); mm != m_mediaInfo.end(); ++mm) {
740 if (codecName == mm->mediaFormat) {
741 mm->preferenceOrder = codecIndex;
742 bool changedSomething = false;
743 for (PINDEX i = 0; i < mm->mediaFormat.GetOptionCount(); i++) {
744 const OpalMediaOption & option = mm->mediaFormat.GetOption(i);
745 if (!option.IsReadOnly()) {
746 PwxString codecOptionName = option.GetName();
747 PwxString codecOptionValue;
748 PString oldOptionValue;
749 mm->mediaFormat.GetOptionValue(codecOptionName, oldOptionValue);
750 if (config->Read(codecOptionName, &codecOptionValue) &&
751 !codecOptionValue.empty() && codecOptionValue != oldOptionValue) {
752 if (mm->mediaFormat.SetOptionValue(codecOptionName, codecOptionValue))
753 changedSomething = true;
757 if (changedSomething)
758 OpalMediaFormat::SetRegisteredMediaFormat(mm->mediaFormat);
762 config->SetPath("..");
763 codecIndex++;
766 if (codecIndex > 0)
767 ApplyMediaInfo();
768 else {
769 PStringArray mediaFormatOrder = GetMediaFormatOrder();
770 for (PINDEX i = 0; i < mediaFormatOrder.GetSize(); i++) {
771 for (MyMediaList::iterator mm = m_mediaInfo.begin(); mm != m_mediaInfo.end(); ++mm) {
772 if (mm->mediaFormat == mediaFormatOrder[i])
773 mm->preferenceOrder = codecIndex++;
776 for (MyMediaList::iterator mm = m_mediaInfo.begin(); mm != m_mediaInfo.end(); ++mm) {
777 if (mm->preferenceOrder < 0)
778 mm->preferenceOrder = codecIndex++;
780 m_mediaInfo.sort();
783 #if PTRACING
784 mediaFormats = OpalMediaFormat::GetAllRegisteredMediaFormats();
785 ostream & traceStream = PTrace::Begin(1, __FILE__, __LINE__);
786 traceStream << "OpenPhone\tRegistered media formats:\n";
787 for (PINDEX i = 0; i < mediaFormats.GetSize(); i++) {
788 traceStream << " " << mediaFormats[i] << '\n';
789 for (PINDEX j = 0; j < mediaFormats[i].GetOptionCount(); j++) {
790 const OpalMediaOption & option = mediaFormats[i].GetOption(j);
791 traceStream << " " << option.GetName() << " = " << option.AsString() << '\n';
794 traceStream << PTrace::End;
795 #endif
797 ////////////////////////////////////////
798 // H.323 fields
799 config->SetPath(H323AliasesGroup);
800 if (config->GetFirstEntry(entryName, entryIndex)) {
801 do {
802 wxString alias;
803 if (config->Read(entryName, &alias) && !alias.empty())
804 h323EP->AddAliasName(alias.c_str());
805 } while (config->GetNextEntry(entryName, entryIndex));
808 config->SetPath(H323Group);
809 if (config->Read(DTMFSendModeKey, &value1) && value1 >= 0 && value1 < H323Connection::NumSendUserInputModes)
810 h323EP->SetSendUserInputMode((H323Connection::SendUserInputModes)value1);
811 if (config->Read(CallIntrusionProtectionLevelKey, &value1))
812 h323EP->SetCallIntrusionProtectionLevel(value1);
813 if (config->Read(DisableFastStartKey, &onoff))
814 h323EP->DisableFastStart(onoff);
815 if (config->Read(DisableH245TunnelingKey, &onoff))
816 h323EP->DisableH245Tunneling(onoff);
817 if (config->Read(DisableH245inSETUPKey, &onoff))
818 h323EP->DisableH245inSetup(onoff);
820 PwxString username, password;
821 config->Read(GatekeeperModeKey, &m_gatekeeperMode, 0);
822 if (m_gatekeeperMode > 0) {
823 if (config->Read(GatekeeperTTLKey, &value1))
824 h323EP->SetGatekeeperTimeToLive(PTimeInterval(0, value1));
826 config->Read(GatekeeperLoginKey, &username, "");
827 config->Read(GatekeeperPasswordKey, &password, "");
828 h323EP->SetGatekeeperPassword(password, username);
830 config->Read(GatekeeperAddressKey, &m_gatekeeperAddress, "");
831 config->Read(GatekeeperIdentifierKey, &m_gatekeeperIdentifier, "");
832 if (!StartGatekeeper())
833 return false;
836 ////////////////////////////////////////
837 // SIP fields
838 config->SetPath(SIPGroup);
839 const SIPURL & proxy = sipEP->GetProxy();
840 PwxString hostname;
841 config->Read(SIPProxyUsedKey, &m_SIPProxyUsed, false);
842 config->Read(SIPProxyKey, &hostname, PwxString(proxy.GetHostName()));
843 config->Read(SIPProxyUsernameKey, &username, PwxString(proxy.GetUserName()));
844 config->Read(SIPProxyPasswordKey, &password, PwxString(proxy.GetPassword()));
845 if (m_SIPProxyUsed)
846 sipEP->SetProxy(hostname, username, password);
848 if (config->Read(RegistrarTimeToLiveKey, &value1))
849 sipEP->SetRegistrarTimeToLive(PTimeInterval(0, value1));
851 if (config->Read(RegistrarUsedKey, &m_registrarUsed, false) &&
852 config->Read(RegistrarNameKey, &m_registrarName) &&
853 config->Read(RegistrarUsernameKey, &m_registrarUser) &&
854 config->Read(RegistrarPasswordKey, &m_registrarPassword))
855 StartRegistrar();
857 ////////////////////////////////////////
858 // Routing fields
860 #if OPAL_SIP
861 if (sipEP != NULL) {
862 AddRouteEntry("pots:.*\\*.*\\*.* = sip:<dn2ip>");
863 AddRouteEntry("pots:.* = sip:<da>");
864 AddRouteEntry("pc:.* = sip:<da>");
866 #if OPAL_H323
867 else
868 #endif
869 #endif
871 #if OPAL_H323
872 if (h323EP != NULL) {
873 AddRouteEntry("pots:.*\\*.*\\*.* = h323:<dn2ip>");
874 AddRouteEntry("pots:.* = h323:<da>");
875 AddRouteEntry("pc:.* = h323:<da>");
877 #endif
879 #if P_EXPAT
880 if (ivrEP != NULL)
881 AddRouteEntry(".*:# = ivr:"); // A hash from anywhere goes to IVR
882 #endif
884 if (potsEP != NULL && potsEP->GetLine("*") != NULL) {
885 #if OPAL_H323
886 AddRouteEntry("h323:.* = pots:<da>");
887 #endif
888 #if OPAL_SIP
889 AddRouteEntry("sip:.* = pots:<da>");
890 #endif
892 else if (pcssEP != NULL) {
893 #if OPAL_H323
894 AddRouteEntry("h323:.* = pc:<da>");
895 #endif
896 #if OPAL_SIP
897 AddRouteEntry("sip:.* = pc:<da>");
898 #endif
902 return true;
906 void MyManager::StartAllListeners()
908 #if OPAL_H323
909 h323EP->RemoveListener(NULL);
910 if (h323EP->StartListeners(m_LocalInterfaces))
911 LogWindow << "H.323 listening on " << setfill(',') << h323EP->GetListeners() << setfill(' ') << endl;
912 else {
913 LogWindow << "H.323 listen failed";
914 if (!m_LocalInterfaces.IsEmpty())
915 LogWindow << " with interfaces" << setfill(',') << m_LocalInterfaces << setfill(' ');
916 LogWindow << endl;
918 #endif
920 #if OPAL_SIP
921 sipEP->RemoveListener(NULL);
922 if (sipEP->StartListeners(m_LocalInterfaces))
923 LogWindow << "SIP listening on " << setfill(',') << sipEP->GetListeners() << setfill(' ') << endl;
924 else {
925 LogWindow << "SIP listen failed";
926 if (!m_LocalInterfaces.IsEmpty())
927 LogWindow << " with interfaces" << setfill(',') << m_LocalInterfaces << setfill(' ');
928 LogWindow << endl;
930 #endif
934 void MyManager::RecreateSpeedDials(SpeedDialViews view)
936 wxConfigBase * config = wxConfig::Get();
937 config->SetPath(AppearanceGroup);
939 config->Write(ActiveViewKey, view);
941 wxListCtrl * oldSpeedDials = m_speedDials;
943 static DWORD const ListCtrlStyle[e_NumViews] = {
944 wxLC_ICON, wxLC_SMALL_ICON, wxLC_LIST, wxLC_REPORT
947 m_speedDials = new wxListCtrl(m_splitter, SpeedDialsID,
948 wxDefaultPosition, wxDefaultSize,
949 ListCtrlStyle[view] | wxLC_EDIT_LABELS | wxSUNKEN_BORDER);
951 if (view != e_ViewDetails) {
952 m_speedDials->SetImageList(m_imageListNormal, wxIMAGE_LIST_NORMAL);
953 m_speedDials->SetImageList(m_imageListSmall, wxIMAGE_LIST_SMALL);
956 int width;
957 static const char * const titles[e_NumColumns] = { "Name", "Number", "Address", "Description" };
959 for (int i = 0; i < e_NumColumns; i++) {
960 m_speedDials->InsertColumn(i, titles[i]);
961 wxString key;
962 key.sprintf("ColumnWidth%u", i);
963 if (config->Read(key, &width))
964 m_speedDials->SetColumnWidth(i, width);
967 // Now either replace the top half of the splitter or set it for the first time
968 if (oldSpeedDials == NULL)
969 m_splitter->SplitHorizontally(m_speedDials, m_logWindow);
970 else {
971 m_splitter->ReplaceWindow(oldSpeedDials, m_speedDials);
972 delete oldSpeedDials;
975 if (config->Read(SashPositionKey, &width))
976 m_splitter->SetSashPosition(width);
978 // Read the speed dials from the configuration
979 config->SetPath(SpeedDialsGroup);
980 wxString groupName;
981 long groupIndex;
982 if (config->GetFirstGroup(groupName, groupIndex)) {
983 do {
984 config->SetPath(groupName);
985 wxString number, address, description;
986 if (config->Read(SpeedDialAddressKey, &address) && !address.empty()) {
987 int icon = 0;
988 if (view == e_ViewLarge) {
989 if (address.StartsWith("h323"))
990 icon = 1;
991 else if (address.StartsWith("sip"))
992 icon = 2;
995 int pos = m_speedDials->InsertItem(INT_MAX, groupName, icon);
996 m_speedDials->SetItem(pos, e_NumberColumn, config->Read(SpeedDialNumberKey, ""));
997 m_speedDials->SetItem(pos, e_AddressColumn, address);
998 m_speedDials->SetItem(pos, e_DescriptionColumn, config->Read(SpeedDialDescriptionKey, ""));
1000 config->SetPath("..");
1001 } while (config->GetNextGroup(groupName, groupIndex));
1006 void MyManager::OnClose(wxCloseEvent& /*event*/)
1008 ::wxBeginBusyCursor();
1010 wxConfigBase * config = wxConfig::Get();
1011 config->SetPath(AppearanceGroup);
1013 int x, y;
1014 GetPosition(&x, &y);
1015 config->Write(MainFrameXKey, x);
1016 config->Write(MainFrameYKey, y);
1018 int w, h;
1019 GetSize(&w, &h);
1020 config->Write(MainFrameWidthKey, w);
1021 config->Write(MainFrameHeightKey, h);
1023 Destroy();
1027 void MyManager::OnAdjustMenus(wxMenuEvent& WXUNUSED(event))
1029 wxMenuBar * menubar = GetMenuBar();
1030 menubar->Enable(XRCID("MenuCall"), m_callState == IdleState);
1031 menubar->Enable(XRCID("MenuAnswer"), m_callState == RingingState);
1032 menubar->Enable(XRCID("MenuHangUp"), m_callState == InCallState);
1036 void MyManager::OnMenuQuit(wxCommandEvent& WXUNUSED(event))
1038 Close(TRUE);
1042 void MyManager::OnMenuAbout(wxCommandEvent& WXUNUSED(event))
1044 wxMessageDialog dialog(this,
1045 _T("OpenPhone\nPost Increment (c) 2004"),
1046 _T("About OpenPhone"),
1047 wxOK);
1048 dialog.ShowModal();
1052 void MyManager::OnMenuCall(wxCommandEvent& WXUNUSED(event))
1054 CallDialog dlg(this);
1055 if (dlg.ShowModal() == wxID_OK)
1056 MakeCall(dlg.m_Address);
1060 void MyManager::OnMenuAnswer(wxCommandEvent& WXUNUSED(event))
1062 AnswerCall();
1066 void MyManager::OnMenuHangUp(wxCommandEvent& WXUNUSED(event))
1068 HangUpCall();
1072 void MyManager::OnNewSpeedDial(wxCommandEvent& WXUNUSED(event))
1074 wxString groupName = "New Speed Dial";
1075 unsigned tieBreaker = 0;
1076 int count = m_speedDials->GetItemCount();
1077 int i = 0;
1078 while (i < count) {
1079 if (m_speedDials->GetItemText(i) != groupName)
1080 i++;
1081 else {
1082 groupName.sprintf("New Speed Dial (%u)", ++tieBreaker);
1083 i = 0;
1087 int pos = m_speedDials->InsertItem(INT_MAX, groupName);
1088 m_speedDials->SetItem(pos, e_NumberColumn, "");
1089 m_speedDials->SetItem(pos, e_AddressColumn, "");
1090 m_speedDials->SetItem(pos, e_DescriptionColumn, "");
1091 m_speedDials->EditLabel(pos);
1095 void MyManager::OnViewLarge(wxCommandEvent& event)
1097 GetMenuBar()->Check(event.GetId(), true);
1098 RecreateSpeedDials(e_ViewLarge);
1102 void MyManager::OnViewSmall(wxCommandEvent& event)
1104 GetMenuBar()->Check(event.GetId(), true);
1105 RecreateSpeedDials(e_ViewSmall);
1109 void MyManager::OnViewList(wxCommandEvent& event)
1111 GetMenuBar()->Check(event.GetId(), true);
1112 RecreateSpeedDials(e_ViewList);
1116 void MyManager::OnViewDetails(wxCommandEvent& event)
1118 GetMenuBar()->Check(event.GetId(), true);
1119 RecreateSpeedDials(e_ViewDetails);
1123 void MyManager::OnEditSpeedDial(wxCommandEvent& WXUNUSED(event))
1125 if (m_speedDials->GetSelectedItemCount() == 1)
1126 EditSpeedDial(m_speedDials->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED));
1130 void MyManager::OnSashPositioned(wxSplitterEvent& event)
1132 wxConfigBase * config = wxConfig::Get();
1133 config->SetPath(AppearanceGroup);
1134 config->Write(SashPositionKey, event.GetSashPosition());
1138 void MyManager::OnSpeedDialActivated(wxListEvent& event)
1140 wxListItem item;
1141 item.m_itemId = event.GetIndex();
1142 if (item.m_itemId < 0)
1143 return;
1145 item.m_col = e_AddressColumn;
1146 item.m_mask = wxLIST_MASK_TEXT;
1147 if (m_speedDials->GetItem(item))
1148 MakeCall(item.m_text);
1152 void MyManager::OnSpeedDialColumnResize(wxListEvent& event)
1154 wxConfigBase * config = wxConfig::Get();
1155 config->SetPath(AppearanceGroup);
1156 wxString key;
1157 key.sprintf("ColumnWidth%u", event.GetColumn());
1158 config->Write(key, m_speedDials->GetColumnWidth(event.GetColumn()));
1162 void MyManager::OnRightClick(wxListEvent& event)
1164 wxMenuBar * menuBar = wxXmlResource::Get()->LoadMenuBar("PopUpMenu");
1165 PopupMenu(menuBar->GetMenu(0), event.GetPoint());
1166 delete menuBar;
1170 void MyManager::EditSpeedDial(int index)
1172 if (index < 0)
1173 return;
1175 wxListItem item;
1176 item.m_itemId = index;
1177 item.m_mask = wxLIST_MASK_TEXT;
1179 item.m_col = e_NameColumn;
1180 if (!m_speedDials->GetItem(item))
1181 return;
1183 // Should display a menu, but initially just allow editing
1184 SpeedDialDialog dlg(this);
1186 wxString originalName = dlg.m_Name = item.m_text;
1188 item.m_col = e_NumberColumn;
1189 if (m_speedDials->GetItem(item))
1190 dlg.m_Number = item.m_text;
1192 item.m_col = e_AddressColumn;
1193 if (m_speedDials->GetItem(item))
1194 dlg.m_Address = item.m_text;
1196 item.m_col = e_DescriptionColumn;
1197 if (m_speedDials->GetItem(item))
1198 dlg.m_Description = item.m_text;
1200 if (dlg.ShowModal() == wxID_OK) {
1201 item.m_col = e_NameColumn;
1202 item.m_text = dlg.m_Name;
1203 m_speedDials->SetItem(item);
1205 item.m_col = e_NumberColumn;
1206 item.m_text = dlg.m_Number;
1207 m_speedDials->SetItem(item);
1209 item.m_col = e_AddressColumn;
1210 item.m_text = dlg.m_Address;
1211 m_speedDials->SetItem(item);
1213 item.m_col = e_DescriptionColumn;
1214 item.m_text = dlg.m_Description;
1215 m_speedDials->SetItem(item);
1217 wxConfigBase * config = wxConfig::Get();
1218 config->SetPath(SpeedDialsGroup);
1219 config->DeleteGroup(originalName);
1220 config->SetPath(dlg.m_Name);
1221 config->Write(SpeedDialNumberKey, dlg.m_Number);
1222 config->Write(SpeedDialAddressKey, dlg.m_Address);
1223 config->Write(SpeedDialDescriptionKey, dlg.m_Description);
1228 bool MyManager::HasSpeedDialName(const wxString & name) const
1230 return m_speedDials->FindItem(-1, name) >= 0;
1234 int MyManager::GetSpeedDialIndex(const char * number, const char * ignore) const
1236 int count = m_speedDials->GetItemCount();
1237 wxListItem item;
1238 item.m_mask = wxLIST_MASK_TEXT;
1239 item.m_col = e_NumberColumn;
1240 for (item.m_itemId = 0; item.m_itemId < count; item.m_itemId++) {
1241 if (m_speedDials->GetItem(item)) {
1242 int len = item.m_text.Length();
1243 if (len > 0 && (ignore == NULL || strcmp(ignore, item.m_text) != 0) && strncmp(number, item.m_text, len) == 0)
1244 return item.m_itemId;
1247 return -1;
1251 void MyManager::MakeCall(const PwxString & address)
1253 if (address.IsEmpty())
1254 return;
1256 SetState(CallingState);
1258 LogWindow << "Calling \"" << address << '"' << endl;
1260 if (potsEP != NULL && potsEP->GetLine("*") != NULL)
1261 SetUpCall("pots:*", address, m_currentCallToken);
1262 else
1263 SetUpCall("pc:*", address, m_currentCallToken);
1267 void MyManager::AnswerCall()
1269 if (m_callState != RingingState)
1270 return;
1272 StopRingSound();
1273 SetState(AnsweringState);
1274 pcssEP->AcceptIncomingConnection(m_ringingConnectionToken);
1278 void MyManager::RejectCall()
1280 if (m_callState != RingingState)
1281 return;
1283 ClearCall(m_currentCallToken);
1284 SetState(IdleState);
1288 void MyManager::HangUpCall()
1290 if (m_callState == IdleState)
1291 return;
1293 LogWindow << "Hanging up \"" << m_currentCallToken << '"' << endl;
1294 ClearCall(m_currentCallToken);
1295 SetState(IdleState);
1299 void MyManager::OnRinging(const OpalPCSSConnection & connection)
1301 m_ringingConnectionToken = connection.GetToken();
1302 m_currentCallToken = connection.GetCall().GetToken();
1304 if (m_autoAnswer)
1305 AnswerCall();
1306 else {
1307 PTime now;
1308 LogWindow << "\nIncoming call at " << now.AsString("w h:mma")
1309 << " from " << connection.GetRemotePartyName() << endl;
1311 if (!m_RingSoundFileName.empty()) {
1312 m_RingSoundChannel.Open(m_RingSoundDeviceName, PSoundChannel::Player);
1313 m_RingSoundChannel.PlayFile(m_RingSoundFileName.c_str(), FALSE);
1314 m_RingSoundTimer.RunContinuous(5000);
1317 SetState(RingingState);
1322 void MyManager::OnRingSoundAgain(PTimer &, INT)
1324 m_RingSoundChannel.PlayFile(m_RingSoundFileName.c_str(), FALSE);
1328 void MyManager::StopRingSound()
1330 m_RingSoundTimer.Stop();
1331 m_RingSoundChannel.Close();
1335 BOOL MyManager::OnIncomingConnection(OpalConnection & connection)
1337 if (connection.GetEndPoint().GetPrefixName() == "pots")
1338 LogWindow << "Line interface device \"" << connection.GetRemotePartyName() << "\" has gone off hook." << endl;
1340 return OpalManager::OnIncomingConnection(connection);
1344 void MyManager::OnEstablishedCall(OpalCall & call)
1346 m_currentCallToken = call.GetToken();
1347 LogWindow << "Established call from " << call.GetPartyA() << " to " << call.GetPartyB() << endl;
1348 SetState(InCallState);
1352 void MyManager::OnClearedCall(OpalCall & call)
1354 StopRingSound();
1356 PString name = call.GetPartyB().IsEmpty() ? call.GetPartyA() : call.GetPartyB();
1358 switch (call.GetCallEndReason()) {
1359 case OpalConnection::EndedByRemoteUser :
1360 LogWindow << '"' << name << "\" has cleared the call";
1361 break;
1362 case OpalConnection::EndedByCallerAbort :
1363 LogWindow << '"' << name << "\" has stopped calling";
1364 break;
1365 case OpalConnection::EndedByRefusal :
1366 LogWindow << '"' << name << "\" did not accept your call";
1367 break;
1368 case OpalConnection::EndedByNoAnswer :
1369 LogWindow << '"' << name << "\" did not answer your call";
1370 break;
1371 case OpalConnection::EndedByTransportFail :
1372 LogWindow << "Call with \"" << name << "\" ended abnormally";
1373 break;
1374 case OpalConnection::EndedByCapabilityExchange :
1375 LogWindow << "Could not find common codec with \"" << name << '"';
1376 break;
1377 case OpalConnection::EndedByNoAccept :
1378 LogWindow << "Did not accept incoming call from \"" << name << '"';
1379 break;
1380 case OpalConnection::EndedByAnswerDenied :
1381 LogWindow << "Refused incoming call from \"" << name << '"';
1382 break;
1383 case OpalConnection::EndedByNoUser :
1384 LogWindow << "Gatekeeper could find user \"" << name << '"';
1385 break;
1386 case OpalConnection::EndedByNoBandwidth :
1387 LogWindow << "Call to \"" << name << "\" aborted, insufficient bandwidth.";
1388 break;
1389 case OpalConnection::EndedByUnreachable :
1390 LogWindow << '"' << name << "\" could not be reached.";
1391 break;
1392 case OpalConnection::EndedByNoEndPoint :
1393 LogWindow << "No phone running for \"" << name << '"';
1394 break;
1395 case OpalConnection::EndedByHostOffline :
1396 LogWindow << '"' << name << "\" is not online.";
1397 break;
1398 case OpalConnection::EndedByConnectFail :
1399 LogWindow << "Transport error calling \"" << name << '"';
1400 break;
1401 default :
1402 LogWindow << "Call with \"" << name << "\" completed";
1404 PTime now;
1405 LogWindow << ", on " << now.AsString("w h:mma") << ". Duration "
1406 << setprecision(0) << setw(5) << (now - call.GetStartTime())
1407 << "s." << endl;
1409 SetState(IdleState);
1413 BOOL MyManager::OnOpenMediaStream(OpalConnection & connection, OpalMediaStream & stream)
1415 if (!OpalManager::OnOpenMediaStream(connection, stream))
1416 return FALSE;
1418 PString prefix = connection.GetEndPoint().GetPrefixName();
1419 if (prefix == pcssEP->GetPrefixName())
1420 return TRUE;
1422 LogWindow << "Started ";
1424 if (stream.IsSource())
1425 LogWindow << "receiving ";
1426 else
1427 LogWindow << "sending ";
1429 LogWindow << stream.GetMediaFormat();
1431 if (stream.IsSource())
1432 LogWindow << " from ";
1433 else
1434 LogWindow << " to ";
1436 LogWindow << connection.GetEndPoint().GetPrefixName() << " endpoint" << endl;
1438 return TRUE;
1442 PSafePtr<OpalConnection> MyManager::GetUserConnection()
1444 PSafePtr<OpalCall> call = GetCall();
1445 if (call == NULL)
1446 return NULL;
1448 for (int i = 0; ; i++) {
1449 PSafePtr<OpalConnection> connection = call->GetConnection(0);
1450 if (connection == NULL)
1451 return NULL;
1453 if (PIsDescendant(&(*connection), OpalPCSSConnection) || PIsDescendant(&(*connection), OpalLineConnection))
1454 return connection;
1457 return NULL;
1461 void MyManager::SendUserInput(char tone)
1463 PSafePtr<OpalConnection> connection = GetUserConnection();
1464 if (connection != NULL)
1465 connection->OnUserInputTone(tone, 100);
1469 BOOL MyManager::CreateVideoOutputDevice(const OpalConnection & connection,
1470 const OpalMediaFormat & mediaFormat,
1471 BOOL preview,
1472 PVideoOutputDevice * & device,
1473 BOOL & autoDelete)
1475 if (preview && !m_VideoGrabPreview)
1476 return FALSE;
1478 // We ALWAYS use a Window
1479 device = PVideoOutputDevice::CreateDevice("Window");
1480 if (device != NULL) {
1481 autoDelete = TRUE;
1482 PString name;
1483 #if defined(__WXMSW__)
1484 name.sprintf("MSWIN STYLE=0x%08X ", WS_POPUP|WS_BORDER|WS_SYSMENU|WS_CAPTION);
1485 #endif
1486 name += "TITLE=\"";
1487 name += preview ? "Local" : (const char *)connection.GetRemotePartyName();
1488 name += '"';
1489 if (device->Open(name))
1490 return TRUE;
1492 delete device;
1495 return OpalManager::CreateVideoOutputDevice(connection, mediaFormat, preview, device, autoDelete);
1499 void MyManager::OnUserInputString(OpalConnection & connection, const PString & value)
1501 LogWindow << "User input \"" << value << "\" received from \"" << connection.GetRemotePartyName() << '"' << endl;
1502 OpalManager::OnUserInputString(connection, value);
1506 PString MyManager::ReadUserInput(OpalConnection & connection,
1507 const char * terminators,
1508 unsigned,
1509 unsigned firstDigitTimeout)
1511 // The usual behaviour is to read until a '#' or timeout and that yields the
1512 // entire destination address. However for this application we want to disable
1513 // the timeout and short circuit the need for '#' as the speed dial number is
1514 // always unique.
1516 PTRACE(3, "OpalPhone\tReadUserInput from " << connection);
1518 connection.PromptUserInput(TRUE);
1519 PString digit = connection.GetUserInput(firstDigitTimeout);
1520 connection.PromptUserInput(FALSE);
1522 PString input;
1523 while (!digit.IsEmpty()) {
1524 input += digit;
1526 int index = GetSpeedDialIndex(input, NULL);
1527 if (index >= 0) {
1528 wxListItem nameItem;
1529 nameItem.m_itemId = index;
1530 nameItem.m_mask = wxLIST_MASK_TEXT;
1531 nameItem.m_col = e_NameColumn;
1532 wxListItem addressItem = nameItem;
1533 addressItem.m_col = e_AddressColumn;
1534 if (m_speedDials->GetItem(nameItem) && m_speedDials->GetItem(addressItem)) {
1535 LogWindow << "Calling \"" << nameItem.m_text << "\" using \"" << addressItem.m_text << '"' << endl;
1536 return addressItem.m_text.c_str();
1540 digit = connection.GetUserInput(firstDigitTimeout);
1543 PTRACE(2, "OpalPhone\tReadUserInput timeout (" << firstDigitTimeout << "ms) on " << *this);
1544 return PString::Empty();
1548 void MyManager::SetState(CallState newState)
1550 if (m_callState == newState)
1551 return;
1553 m_callState = newState;
1555 m_speedDials->Show(newState == IdleState);
1556 m_answerPanel->Show(newState == RingingState);
1557 m_callingPanel->Show(newState == CallingState);
1558 m_inCallPanel->Show(newState == InCallState);
1560 wxWindow * newWindow;
1561 switch (newState) {
1562 case RingingState :
1563 newWindow = m_answerPanel;
1564 break;
1566 case InCallState :
1567 newWindow = m_inCallPanel;
1568 break;
1570 case CallingState :
1571 newWindow = m_callingPanel;
1572 break;
1574 default :
1575 newWindow = m_speedDials;
1578 m_splitter->ReplaceWindow(m_splitter->GetWindow1(), newWindow);
1582 bool MyManager::StartGatekeeper()
1584 if (m_gatekeeperMode == 0)
1585 h323EP->RemoveGatekeeper();
1586 else {
1587 LogWindow << "H.323 registration started for " << m_gatekeeperIdentifier;
1588 if (!m_gatekeeperIdentifier.IsEmpty() || !m_gatekeeperAddress.IsEmpty())
1589 LogWindow << '@';
1590 LogWindow << m_gatekeeperAddress << endl;
1592 if (h323EP->UseGatekeeper(m_gatekeeperAddress, m_gatekeeperIdentifier)) {
1593 LogWindow << "H.323 registration successful to " << *h323EP->GetGatekeeper() << endl;
1594 return true;
1598 return m_gatekeeperMode < 2;
1602 bool MyManager::StartRegistrar()
1604 if (m_registrarUsed) {
1605 if (!sipEP->Register(m_registrarName, m_registrarUser, m_registrarUser, m_registrarPassword))
1606 return false;
1608 LogWindow << "SIP registration started for " << m_registrarUser << '@' << m_registrarName << endl;
1610 else {
1611 PString aor = m_registrarUser + '@' + m_registrarName;
1612 if (sipEP->IsRegistered(aor)) {
1613 LogWindow << "SIP registration ended for " << aor << endl;
1614 sipEP->Unregister(aor);
1617 return true;
1621 void MyManager::InitMediaInfo(const char * source, const OpalMediaFormatList & mediaFormats)
1623 for (PINDEX i = 0; i < mediaFormats.GetSize(); i++) {
1624 const OpalMediaFormat & mediaFormat = mediaFormats[i];
1625 if (mediaFormat.GetPayloadType() != RTP_DataFrame::MaxPayloadType)
1626 m_mediaInfo.push_back(MyMedia(source, mediaFormat));
1631 void MyManager::ApplyMediaInfo()
1633 PStringList mediaFormatOrder, mediaFormatMask;
1635 m_mediaInfo.sort();
1637 for (MyMediaList::iterator mm = m_mediaInfo.begin(); mm != m_mediaInfo.end(); ++mm) {
1638 if (mm->preferenceOrder < 0)
1639 mediaFormatMask.AppendString(mm->mediaFormat);
1640 else
1641 mediaFormatOrder.AppendString(mm->mediaFormat);
1644 if (!mediaFormatOrder.IsEmpty()) {
1645 SetMediaFormatOrder(mediaFormatOrder);
1646 SetMediaFormatMask(mediaFormatMask);
1651 ///////////////////////////////////////////////////////////////////////////////
1653 void MyManager::OnOptions(wxCommandEvent& /*event*/)
1655 OptionsDialog dlg(this);
1656 dlg.ShowModal();
1659 BEGIN_EVENT_TABLE(OptionsDialog, wxDialog)
1660 ////////////////////////////////////////
1661 // Networking fields
1662 EVT_CHOICE(XRCID("BandwidthClass"), OptionsDialog::BandwidthClass)
1663 EVT_LISTBOX(XRCID("LocalInterfaces"), OptionsDialog::SelectedLocalInterface)
1664 EVT_TEXT(XRCID("InterfaceToAdd"), OptionsDialog::ChangedInterfaceToAdd)
1665 EVT_BUTTON(XRCID("AddInterface"), OptionsDialog::AddInterface)
1666 EVT_BUTTON(XRCID("RemoveInterface"), OptionsDialog::RemoveInterface)
1668 ////////////////////////////////////////
1669 // Audio fields
1670 EVT_COMBOBOX(XRCID(LineInterfaceDeviceKey), OptionsDialog::SelectedLID)
1672 ////////////////////////////////////////
1673 // Codec fields
1674 EVT_BUTTON(XRCID("BrowseSoundFile"), OptionsDialog::BrowseSoundFile)
1675 EVT_BUTTON(XRCID("PlaySoundFile"), OptionsDialog::PlaySoundFile)
1676 EVT_BUTTON(XRCID("AddCodec"), OptionsDialog::AddCodec)
1677 EVT_BUTTON(XRCID("RemoveCodec"), OptionsDialog::RemoveCodec)
1678 EVT_BUTTON(XRCID("MoveUpCodec"), OptionsDialog::MoveUpCodec)
1679 EVT_BUTTON(XRCID("MoveDownCodec"), OptionsDialog::MoveDownCodec)
1680 EVT_LISTBOX(XRCID("AllCodecs"), OptionsDialog::SelectedCodecToAdd)
1681 EVT_LISTBOX(XRCID("SelectedCodecs"), OptionsDialog::SelectedCodec)
1682 EVT_LIST_ITEM_SELECTED(XRCID("CodecOptionsList"), OptionsDialog::SelectedCodecOption)
1683 EVT_LIST_ITEM_DESELECTED(XRCID("CodecOptionsList"), OptionsDialog::DeselectedCodecOption)
1684 EVT_TEXT(XRCID("CodecOptionValue"), OptionsDialog::ChangedCodecOptionValue)
1686 ////////////////////////////////////////
1687 // Routing fields
1688 EVT_BUTTON(XRCID("AddRoute"), OptionsDialog::AddRoute)
1689 EVT_BUTTON(XRCID("RemoveRoute"), OptionsDialog::RemoveRoute)
1690 EVT_LIST_ITEM_SELECTED(XRCID("Routes"), OptionsDialog::SelectedRoute)
1691 EVT_LIST_ITEM_DESELECTED(XRCID("Routes"), OptionsDialog::DeselectedRoute)
1692 EVT_TEXT(XRCID("RoutePattern"), OptionsDialog::ChangedRouteInfo)
1693 EVT_TEXT(XRCID("RouteDestination"), OptionsDialog::ChangedRouteInfo)
1695 ////////////////////////////////////////
1696 // H.323 fields
1697 EVT_LISTBOX(XRCID("Aliases"), OptionsDialog::SelectedAlias)
1698 EVT_BUTTON(XRCID("AddAlias"), OptionsDialog::AddAlias)
1699 EVT_BUTTON(XRCID("RemoveAlias"), OptionsDialog::RemoveAlias)
1700 EVT_TEXT(XRCID("NewAlias"), OptionsDialog::ChangedNewAlias)
1701 END_EVENT_TABLE()
1704 #define INIT_FIELD(name, value) \
1705 m_##name = value; \
1706 FindWindowByName(name##Key)->SetValidator(wxGenericValidator(&m_##name))
1708 OptionsDialog::OptionsDialog(MyManager * manager)
1709 : m_manager(*manager)
1711 PINDEX i;
1713 SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY);
1714 wxXmlResource::Get()->LoadDialog(this, manager, "OptionsDialog");
1716 ////////////////////////////////////////
1717 // General fields
1718 INIT_FIELD(Username, m_manager.GetDefaultUserName());
1719 INIT_FIELD(DisplayName, m_manager.GetDefaultDisplayName());
1721 PStringList devices = PSoundChannel::GetDeviceNames(PSoundChannel::Player);
1722 wxChoice * choice = FindWindowByNameAs<wxChoice>(this, RingSoundDeviceNameKey);
1723 choice->SetValidator(wxGenericValidator(&m_RingSoundDeviceName));
1724 for (i = 0; i < devices.GetSize(); i++)
1725 choice->Append((const char *)devices[i]);
1726 m_RingSoundDeviceName = m_manager.m_RingSoundDeviceName;
1727 INIT_FIELD(RingSoundFileName, m_manager.m_RingSoundFileName);
1729 INIT_FIELD(AutoAnswer, m_manager.m_autoAnswer);
1730 #if P_EXPAT
1731 INIT_FIELD(IVRScript, m_manager.ivrEP->GetDefaultVXML());
1732 #endif
1734 ////////////////////////////////////////
1735 // Networking fields
1736 int bandwidth = m_manager.h323EP->GetInitialBandwidth();
1737 m_Bandwidth.sprintf(bandwidth%10 == 0 ? "%u" : "%u.%u", bandwidth/10, bandwidth%10);
1738 FindWindowByName(BandwidthKey)->SetValidator(wxTextValidator(wxFILTER_NUMERIC, &m_Bandwidth));
1739 int bandwidthClass;
1740 if (bandwidth <= 144)
1741 bandwidthClass = 0;
1742 else if (bandwidth <= 288)
1743 bandwidthClass = 1;
1744 else if (bandwidth <= 640)
1745 bandwidthClass = 2;
1746 else if (bandwidth <= 1280)
1747 bandwidthClass = 3;
1748 else if (bandwidth <= 15000)
1749 bandwidthClass = 4;
1750 else
1751 bandwidthClass = 5;
1752 FindWindowByNameAs<wxChoice>(this, "BandwidthClass")->SetSelection(bandwidthClass);
1754 INIT_FIELD(TCPPortBase, m_manager.GetTCPPortBase());
1755 INIT_FIELD(TCPPortMax, m_manager.GetTCPPortMax());
1756 INIT_FIELD(UDPPortBase, m_manager.GetUDPPortBase());
1757 INIT_FIELD(UDPPortMax, m_manager.GetUDPPortMax());
1758 INIT_FIELD(RTPPortBase, m_manager.GetRtpIpPortBase());
1759 INIT_FIELD(RTPPortMax, m_manager.GetRtpIpPortMax());
1760 INIT_FIELD(RTPTOS, m_manager.GetRtpIpTypeofService());
1761 INIT_FIELD(STUNServer, m_manager.GetSTUN() != NULL ? m_manager.GetSTUN()->GetServer() : PString());
1762 PwxString natRouter;
1763 if (m_manager.GetTranslationAddress().IsValid())
1764 natRouter = m_manager.GetTranslationAddress().AsString();
1765 INIT_FIELD(NATRouter, natRouter);
1767 m_AddInterface = FindWindowByNameAs<wxButton>(this, "AddInterface");
1768 m_AddInterface->Disable();
1769 m_RemoveInterface = FindWindowByNameAs<wxButton>(this, "RemoveInterface");
1770 m_RemoveInterface->Disable();
1771 m_InterfaceToAdd = FindWindowByNameAs<wxTextCtrl>(this, "InterfaceToAdd");
1772 m_LocalInterfaces = FindWindowByNameAs<wxListBox>(this, "LocalInterfaces");
1773 for (i = 0; i < m_manager.m_LocalInterfaces.GetSize(); i++)
1774 m_LocalInterfaces->Append((const char *)m_manager.m_LocalInterfaces[i]);
1776 ////////////////////////////////////////
1777 // Sound fields
1778 INIT_FIELD(SoundBuffers, m_manager.pcssEP->GetSoundChannelBufferDepth());
1779 INIT_FIELD(MinJitter, m_manager.GetMinAudioJitterDelay());
1780 INIT_FIELD(MaxJitter, m_manager.GetMaxAudioJitterDelay());
1781 INIT_FIELD(SilenceSuppression, m_manager.GetSilenceDetectParams().m_mode);
1782 INIT_FIELD(SilenceThreshold, m_manager.GetSilenceDetectParams().m_threshold);
1783 INIT_FIELD(SignalDeadband, m_manager.GetSilenceDetectParams().m_signalDeadband/8);
1784 INIT_FIELD(SilenceDeadband, m_manager.GetSilenceDetectParams().m_silenceDeadband/8);
1786 // Fill sound player combo box with available devices and set selection
1787 wxComboBox * combo = FindWindowByNameAs<wxComboBox>(this, SoundPlayerKey);
1788 combo->SetValidator(wxGenericValidator(&m_SoundPlayer));
1789 for (i = 0; i < devices.GetSize(); i++)
1790 combo->Append((const char *)devices[i]);
1791 m_SoundPlayer = m_manager.pcssEP->GetSoundChannelPlayDevice();
1793 // Fill sound recorder combo box with available devices and set selection
1794 combo = FindWindowByNameAs<wxComboBox>(this, SoundRecorderKey);
1795 combo->SetValidator(wxGenericValidator(&m_SoundRecorder));
1796 devices = PSoundChannel::GetDeviceNames(PSoundChannel::Recorder);
1797 for (i = 0; i < devices.GetSize(); i++)
1798 combo->Append((const char *)devices[i]);
1799 m_SoundRecorder = m_manager.pcssEP->GetSoundChannelRecordDevice();
1801 // Fill line interface combo box with available devices and set selection
1802 m_selectedAEC = FindWindowByNameAs<wxChoice>(this, AECKey);
1803 m_selectedCountry = FindWindowByNameAs<wxComboBox>(this, CountryKey);
1804 m_selectedCountry->SetValidator(wxGenericValidator(&m_Country));
1805 m_selectedLID = FindWindowByNameAs<wxComboBox>(this, LineInterfaceDeviceKey);
1806 m_selectedLID->SetValidator(wxGenericValidator(&m_LineInterfaceDevice));
1807 devices = OpalLineInterfaceDevice::GetAllDevices();
1808 if (devices.IsEmpty()) {
1809 m_LineInterfaceDevice = "<< None available >>";
1810 m_selectedLID->Append(m_LineInterfaceDevice);
1811 m_selectedAEC->Disable();
1812 m_selectedCountry->Disable();
1814 else {
1815 static const char UseSoundCard[] = "<< Use sound card only >>";
1816 m_selectedLID->Append(UseSoundCard);
1817 for (i = 0; i < devices.GetSize(); i++)
1818 m_selectedLID->Append((const char *)devices[i]);
1820 OpalLine * line = m_manager.potsEP->GetLine("*");
1821 if (line != NULL) {
1822 m_LineInterfaceDevice = line->GetDevice().GetDeviceType() + ": " + line->GetDevice().GetDeviceName();
1823 for (i = 0; i < devices.GetSize(); i++) {
1824 if (m_LineInterfaceDevice == devices[i])
1825 break;
1827 if (i >= devices.GetSize()) {
1828 for (i = 0; i < devices.GetSize(); i++) {
1829 if (devices[i].Find(m_LineInterfaceDevice.c_str()) == 0)
1830 break;
1832 if (i >= devices.GetSize())
1833 m_LineInterfaceDevice = devices[0];
1836 INIT_FIELD(AEC, line->GetAEC());
1838 PStringList countries = line->GetDevice().GetCountryCodeNameList();
1839 for (i = 0; i < countries.GetSize(); i++)
1840 m_selectedCountry->Append((const char *)countries[i]);
1841 INIT_FIELD(Country, line->GetDevice().GetCountryCodeName());
1843 else {
1844 m_LineInterfaceDevice = UseSoundCard;
1845 m_selectedAEC->Disable();
1846 m_selectedCountry->Disable();
1850 ////////////////////////////////////////
1851 // Video fields
1852 INIT_FIELD(VideoGrabber, m_manager.GetVideoInputDevice().deviceName);
1853 INIT_FIELD(VideoGrabFormat, m_manager.GetVideoInputDevice().videoFormat);
1854 INIT_FIELD(VideoGrabSource, m_manager.GetVideoInputDevice().channelNumber);
1855 INIT_FIELD(VideoGrabFrameRate, m_manager.GetVideoInputDevice().rate);
1856 INIT_FIELD(VideoFlipLocal, m_manager.GetVideoInputDevice().flip != FALSE);
1857 INIT_FIELD(VideoGrabPreview, m_manager.m_VideoGrabPreview);
1858 INIT_FIELD(VideoAutoTransmit, m_manager.CanAutoStartTransmitVideo() != FALSE);
1859 INIT_FIELD(VideoAutoReceive, m_manager.CanAutoStartReceiveVideo() != FALSE);
1860 INIT_FIELD(VideoFlipRemote, m_manager.GetVideoOutputDevice().flip != FALSE);
1862 choice = FindWindowByNameAs<wxChoice>(this, "VideoGrabber");
1863 devices = PVideoInputDevice::GetDriversDeviceNames("*");
1864 for (i = 0; i < devices.GetSize(); i++)
1865 choice->Append((const char *)devices[i]);
1867 ////////////////////////////////////////
1868 // Codec fields
1869 m_AddCodec = FindWindowByNameAs<wxButton>(this, "AddCodec");
1870 m_AddCodec->Disable();
1871 m_RemoveCodec = FindWindowByNameAs<wxButton>(this, "RemoveCodec");
1872 m_RemoveCodec->Disable();
1873 m_MoveUpCodec = FindWindowByNameAs<wxButton>(this, "MoveUpCodec");
1874 m_MoveUpCodec->Disable();
1875 m_MoveDownCodec = FindWindowByNameAs<wxButton>(this, "MoveDownCodec");
1876 m_MoveDownCodec->Disable();
1878 m_allCodecs = FindWindowByNameAs<wxListBox>(this, "AllCodecs");
1879 m_selectedCodecs = FindWindowByNameAs<wxListBox>(this, "SelectedCodecs");
1880 for (MyMediaList::iterator mm = m_manager.m_mediaInfo.begin(); mm != m_manager.m_mediaInfo.end(); ++mm) {
1881 wxString str = mm->sourceProtocol;
1882 str += ": ";
1883 str += (const char *)mm->mediaFormat;
1884 m_allCodecs->Append(str, &*mm);
1886 str = (const char *)mm->mediaFormat;
1887 if (mm->preferenceOrder >= 0 && m_selectedCodecs->FindString(str) < 0)
1888 m_selectedCodecs->Append(str, &*mm);
1890 m_codecOptions = FindWindowByNameAs<wxListCtrl>(this, "CodecOptionsList");
1891 int columnWidth = (m_codecOptions->GetClientSize().GetWidth()-30)/2;
1892 m_codecOptions->InsertColumn(0, "Option", wxLIST_FORMAT_LEFT, columnWidth);
1893 m_codecOptions->InsertColumn(1, "Value", wxLIST_FORMAT_LEFT, columnWidth);
1894 m_codecOptionValue = FindWindowByNameAs<wxTextCtrl>(this, "CodecOptionValue");
1895 m_codecOptionValue->Disable();
1897 ////////////////////////////////////////
1898 // H.323 fields
1899 m_AddAlias = FindWindowByNameAs<wxButton>(this, "AddAlias");
1900 m_AddAlias->Disable();
1901 m_RemoveAlias = FindWindowByNameAs<wxButton>(this, "RemoveAlias");
1902 m_RemoveAlias->Disable();
1903 m_NewAlias = FindWindowByNameAs<wxTextCtrl>(this, "NewAlias");
1904 m_Aliases = FindWindowByNameAs<wxListBox>(this, "Aliases");
1905 PStringList aliases = m_manager.h323EP->GetAliasNames();
1906 for (i = 1; i < aliases.GetSize(); i++)
1907 m_Aliases->Append((const char *)aliases[i]);
1909 INIT_FIELD(DTMFSendMode, m_manager.h323EP->GetSendUserInputMode());
1910 INIT_FIELD(CallIntrusionProtectionLevel, m_manager.h323EP->GetCallIntrusionProtectionLevel());
1911 INIT_FIELD(DisableFastStart, m_manager.h323EP->IsFastStartDisabled() != FALSE);
1912 INIT_FIELD(DisableH245Tunneling, m_manager.h323EP->IsH245TunnelingDisabled() != FALSE);
1913 INIT_FIELD(DisableH245inSETUP, m_manager.h323EP->IsH245inSetupDisabled() != FALSE);
1914 INIT_FIELD(GatekeeperMode, m_manager.m_gatekeeperMode);
1915 INIT_FIELD(GatekeeperAddress, m_manager.m_gatekeeperAddress);
1916 INIT_FIELD(GatekeeperIdentifier, m_manager.m_gatekeeperIdentifier);
1917 INIT_FIELD(GatekeeperTTL, m_manager.h323EP->GetGatekeeperTimeToLive().GetSeconds());
1918 INIT_FIELD(GatekeeperLogin, m_manager.h323EP->GetGatekeeperUsername());
1919 INIT_FIELD(GatekeeperPassword, m_manager.h323EP->GetGatekeeperPassword());
1921 ////////////////////////////////////////
1922 // SIP fields
1923 INIT_FIELD(SIPProxyUsed, m_manager.m_SIPProxyUsed);
1924 INIT_FIELD(SIPProxy, m_manager.sipEP->GetProxy().GetHostName());
1925 INIT_FIELD(SIPProxyUsername, m_manager.sipEP->GetProxy().GetUserName());
1926 INIT_FIELD(SIPProxyPassword, m_manager.sipEP->GetProxy().GetPassword());
1927 INIT_FIELD(RegistrarUsed, m_manager.m_registrarUsed);
1928 INIT_FIELD(RegistrarName, m_manager.m_registrarName);
1929 INIT_FIELD(RegistrarUsername, m_manager.m_registrarUser);
1930 INIT_FIELD(RegistrarPassword, m_manager.m_registrarPassword);
1931 INIT_FIELD(RegistrarTimeToLive, m_manager.sipEP->GetRegistrarTimeToLive().GetSeconds());
1933 ////////////////////////////////////////
1934 // Routing fields
1935 m_SelectedRoute = INT_MAX;
1937 m_RoutePattern = FindWindowByNameAs<wxTextCtrl>(this, "RoutePattern");
1938 m_RouteDestination = FindWindowByNameAs<wxTextCtrl>(this, "RouteDestination");
1940 m_AddRoute = FindWindowByNameAs<wxButton>(this, "AddRoute");
1941 m_AddRoute->Disable();
1943 m_RemoveRoute = FindWindowByNameAs<wxButton>(this, "RemoveRoute");
1944 m_RemoveRoute->Disable();
1946 // Fill list box with active routes
1947 static char const AllSources[] = "<ALL>";
1948 m_Routes = FindWindowByNameAs<wxListCtrl>(this, "Routes");
1949 m_Routes->InsertColumn(0, _T("Source"));
1950 m_Routes->InsertColumn(1, _T("Pattern"));
1951 m_Routes->InsertColumn(2, _T("Destination"));
1952 const OpalManager::RouteTable & routeTable = m_manager.GetRouteTable();
1953 for (i = 0; i < routeTable.GetSize(); i++) {
1954 PString pattern = routeTable[i].pattern;
1955 PINDEX colon = pattern.Find(':');
1956 wxString source;
1957 if (colon == P_MAX_INDEX) {
1958 source = AllSources;
1959 colon = 0;
1961 else {
1962 source = (const char *)pattern.Left(colon);
1963 if (source == ".*")
1964 source = AllSources;
1965 ++colon;
1967 int pos = m_Routes->InsertItem(INT_MAX, source);
1968 m_Routes->SetItem(pos, 1, (const char *)pattern.Mid(colon));
1969 m_Routes->SetItem(pos, 2, (const char *)routeTable[i].destination);
1972 // Fill combo box with possible protocols
1973 m_RouteSource = FindWindowByNameAs<wxComboBox>(this, "RouteSource");
1974 m_RouteSource->Append(AllSources);
1975 const PList<OpalEndPoint> & endponts = m_manager.GetEndPoints();
1976 for (i = 0; i < endponts.GetSize(); i++)
1977 m_RouteSource->Append((const char *)endponts[i].GetPrefixName());
1978 m_RouteSource->SetSelection(0);
1981 #if PTRACING
1982 ////////////////////////////////////////
1983 // Tracing fields
1984 INIT_FIELD(EnableTracing, m_manager.m_enableTracing);
1985 INIT_FIELD(TraceLevelThreshold, PTrace::GetLevel());
1986 INIT_FIELD(TraceLevelNumber, (PTrace::GetOptions()&PTrace::TraceLevel) != 0);
1987 INIT_FIELD(TraceFileLine, (PTrace::GetOptions()&PTrace::FileAndLine) != 0);
1988 INIT_FIELD(TraceBlocks, (PTrace::GetOptions()&PTrace::Blocks) != 0);
1989 INIT_FIELD(TraceDateTime, (PTrace::GetOptions()&PTrace::DateAndTime) != 0);
1990 INIT_FIELD(TraceTimestamp, (PTrace::GetOptions()&PTrace::Timestamp) != 0);
1991 INIT_FIELD(TraceThreadName, (PTrace::GetOptions()&PTrace::Thread) != 0);
1992 INIT_FIELD(TraceThreadAddress, (PTrace::GetOptions()&PTrace::ThreadAddress) != 0);
1993 INIT_FIELD(TraceFileName, m_manager.m_traceFileName);
1994 #else
1995 wxNotebook * book = FindWindowByNameAs<wxNotebook>(this, "OptionsNotebook");
1996 book->DeletePage(book->GetPageCount()-1);
1997 #endif // PTRACING
2001 #define SAVE_FIELD(name, set) \
2002 set(m_##name); \
2003 config->Write(name##Key, m_##name)
2005 #define SAVE_FIELD2(name1, name2, set) \
2006 set(m_##name1, m_##name2); \
2007 config->Write(name1##Key, m_##name1); \
2008 config->Write(name2##Key, m_##name2)
2010 bool OptionsDialog::TransferDataFromWindow()
2012 if (!wxDialog::TransferDataFromWindow())
2013 return false;
2015 double floatBandwidth;
2016 if (!m_Bandwidth.ToDouble(&floatBandwidth) || floatBandwidth < 10)
2017 return false;
2019 ::wxBeginBusyCursor();
2021 wxConfigBase * config = wxConfig::Get();
2023 ////////////////////////////////////////
2024 // General fields
2025 config->SetPath(GeneralGroup);
2026 SAVE_FIELD(Username, m_manager.SetDefaultUserName);
2027 SAVE_FIELD(DisplayName, m_manager.SetDefaultDisplayName);
2028 SAVE_FIELD(RingSoundDeviceName, m_manager.m_RingSoundDeviceName = );
2029 SAVE_FIELD(RingSoundFileName, m_manager.m_RingSoundFileName = );
2030 SAVE_FIELD(AutoAnswer, m_manager.m_autoAnswer = );
2031 #if P_EXPAT
2032 SAVE_FIELD(IVRScript, m_manager.ivrEP->SetDefaultVXML);
2033 #endif
2035 ////////////////////////////////////////
2036 // Networking fields
2037 config->SetPath(NetworkingGroup);
2038 int adjustedBandwidth = (int)(floatBandwidth*10);
2039 m_manager.h323EP->SetInitialBandwidth(adjustedBandwidth);
2040 config->Write(BandwidthKey, adjustedBandwidth);
2041 SAVE_FIELD2(TCPPortBase, TCPPortMax, m_manager.SetTCPPorts);
2042 SAVE_FIELD2(UDPPortBase, UDPPortMax, m_manager.SetUDPPorts);
2043 SAVE_FIELD2(RTPPortBase, RTPPortMax, m_manager.SetRtpIpPorts);
2044 SAVE_FIELD(RTPTOS, m_manager.SetRtpIpTypeofService);
2045 SAVE_FIELD(STUNServer, m_manager.SetSTUNServer);
2046 SAVE_FIELD(NATRouter, m_manager.SetTranslationAddress);
2048 config->DeleteGroup(LocalInterfacesGroup);
2049 config->SetPath(LocalInterfacesGroup);
2050 PStringArray newInterfaces(m_LocalInterfaces->GetCount());
2051 bool changed = m_manager.m_LocalInterfaces.GetSize() != newInterfaces.GetSize();
2052 for (int i = 0; i < newInterfaces.GetSize(); i++) {
2053 newInterfaces[i] = m_LocalInterfaces->GetString(i);
2054 if (newInterfaces[i] != m_manager.m_LocalInterfaces)
2055 changed = true;
2056 wxString key;
2057 key.sprintf("%u", i+1);
2058 config->Write(key, (const char *)newInterfaces[i]);
2060 if (changed) {
2061 m_manager.m_LocalInterfaces = newInterfaces;
2062 m_manager.StartAllListeners();
2065 ////////////////////////////////////////
2066 // Sound fields
2067 config->SetPath(AudioGroup);
2068 SAVE_FIELD(SoundPlayer, m_manager.pcssEP->SetSoundChannelPlayDevice);
2069 SAVE_FIELD(SoundRecorder, m_manager.pcssEP->SetSoundChannelRecordDevice);
2070 SAVE_FIELD(SoundBuffers, m_manager.pcssEP->SetSoundChannelBufferDepth);
2071 SAVE_FIELD2(MinJitter, MaxJitter, m_manager.SetAudioJitterDelay);
2073 OpalSilenceDetector::Params silenceParams;
2074 SAVE_FIELD(SilenceSuppression, silenceParams.m_mode=(OpalSilenceDetector::Mode));
2075 SAVE_FIELD(SilenceThreshold, silenceParams.m_threshold=);
2076 SAVE_FIELD(SignalDeadband, silenceParams.m_signalDeadband=8*);
2077 SAVE_FIELD(SilenceDeadband, silenceParams.m_silenceDeadband=8*);
2078 m_manager.SetSilenceDetectParams(silenceParams);
2080 config->Write(LineInterfaceDeviceKey, m_LineInterfaceDevice);
2081 if (m_manager.potsEP->AddDeviceName(m_LineInterfaceDevice)) {
2082 OpalLine * line = m_manager.potsEP->GetLine("*");
2083 if (PAssertNULL(line) != NULL) {
2084 line->SetAEC((OpalLineInterfaceDevice::AECLevels)m_AEC);
2085 config->Write(AECKey, m_AEC);
2086 if (!line->GetDevice().SetCountryCodeName(m_Country))
2087 LogWindow << "Could not configure Line Interface Device to country \"" << m_Country << '"' << endl;
2088 config->Write(CountryKey, m_Country);
2092 ////////////////////////////////////////
2093 // Video fields
2094 config->SetPath(VideoGroup);
2095 PVideoDevice::OpenArgs grabber = m_manager.GetVideoInputDevice();
2096 SAVE_FIELD(VideoGrabber, grabber.deviceName = (const char *));
2097 SAVE_FIELD(VideoGrabFormat, grabber.videoFormat = (PVideoDevice::VideoFormat));
2098 SAVE_FIELD(VideoGrabSource, grabber.channelNumber = );
2099 SAVE_FIELD(VideoGrabFrameRate, grabber.rate = );
2100 SAVE_FIELD(VideoFlipLocal, grabber.flip = );
2101 m_manager.SetVideoInputDevice(grabber);
2102 SAVE_FIELD(VideoGrabPreview, m_manager.m_VideoGrabPreview = );
2103 SAVE_FIELD(VideoAutoTransmit, m_manager.SetAutoStartTransmitVideo);
2104 SAVE_FIELD(VideoAutoReceive, m_manager.SetAutoStartReceiveVideo);
2105 // SAVE_FIELD(VideoFlipRemote, );
2107 ////////////////////////////////////////
2108 // Codec fields
2109 MyMediaList::iterator mm;
2110 for (mm = m_manager.m_mediaInfo.begin(); mm != m_manager.m_mediaInfo.end(); ++mm)
2111 mm->preferenceOrder = -1;
2113 size_t codecIndex;
2114 for (codecIndex = 0; codecIndex < m_selectedCodecs->GetCount(); codecIndex++) {
2115 PwxString selectedFormat = m_selectedCodecs->GetString(codecIndex);
2116 for (mm = m_manager.m_mediaInfo.begin(); mm != m_manager.m_mediaInfo.end(); ++mm) {
2117 if (selectedFormat == mm->mediaFormat) {
2118 mm->preferenceOrder = codecIndex;
2119 break;
2124 m_manager.ApplyMediaInfo();
2126 config->DeleteGroup(CodecsGroup);
2127 for (mm = m_manager.m_mediaInfo.begin(); mm != m_manager.m_mediaInfo.end(); ++mm) {
2128 if (mm->preferenceOrder >= 0) {
2129 wxString groupName;
2130 groupName.sprintf("%s/%04u", CodecsGroup, mm->preferenceOrder);
2131 config->SetPath(groupName);
2132 config->Write(CodecNameKey, (const char *)mm->mediaFormat);
2133 for (PINDEX i = 0; i < mm->mediaFormat.GetOptionCount(); i++) {
2134 const OpalMediaOption & option = mm->mediaFormat.GetOption(i);
2135 if (!option.IsReadOnly())
2136 config->Write(PwxString(option.GetName()), PwxString(option.AsString()));
2138 if (mm->dirty) {
2139 OpalMediaFormat::SetRegisteredMediaFormat(mm->mediaFormat);
2140 mm->dirty = false;
2146 ////////////////////////////////////////
2147 // H.323 fields
2148 config->DeleteGroup(H323AliasesGroup);
2149 config->SetPath(H323AliasesGroup);
2150 m_manager.h323EP->SetLocalUserName(m_Username);
2151 PStringList aliases = m_manager.h323EP->GetAliasNames();
2152 for (size_t i = 0; i < m_Aliases->GetCount(); i++) {
2153 wxString alias = m_Aliases->GetString(i);
2154 m_manager.h323EP->AddAliasName(alias.c_str());
2155 wxString key;
2156 key.sprintf("%u", i+1);
2157 config->Write(key, alias);
2160 config->SetPath(H323Group);
2161 m_manager.h323EP->SetSendUserInputMode((H323Connection::SendUserInputModes)m_DTMFSendMode);
2162 config->Write(DTMFSendModeKey, m_DTMFSendMode);
2163 SAVE_FIELD(CallIntrusionProtectionLevel, m_manager.h323EP->SetCallIntrusionProtectionLevel);
2164 SAVE_FIELD(DisableFastStart, m_manager.h323EP->DisableFastStart);
2165 SAVE_FIELD(DisableH245Tunneling, m_manager.h323EP->DisableH245Tunneling);
2166 SAVE_FIELD(DisableH245inSETUP, m_manager.h323EP->DisableH245inSetup);
2168 config->Write(GatekeeperTTLKey, m_GatekeeperTTL);
2169 m_manager.h323EP->SetGatekeeperTimeToLive(PTimeInterval(0, m_GatekeeperTTL));
2171 if (m_manager.m_gatekeeperMode != m_GatekeeperMode ||
2172 m_manager.m_gatekeeperAddress != m_GatekeeperAddress ||
2173 m_manager.m_gatekeeperIdentifier != m_GatekeeperIdentifier ||
2174 m_manager.h323EP->GetGatekeeperUsername() != m_GatekeeperLogin.c_str() ||
2175 m_manager.h323EP->GetGatekeeperPassword() != m_GatekeeperPassword.c_str()) {
2176 SAVE_FIELD(GatekeeperMode, m_manager.m_gatekeeperMode = );
2177 SAVE_FIELD(GatekeeperAddress, m_manager.m_gatekeeperAddress = );
2178 SAVE_FIELD(GatekeeperIdentifier, m_manager.m_gatekeeperIdentifier = );
2179 SAVE_FIELD2(GatekeeperPassword, GatekeeperLogin, m_manager.h323EP->SetGatekeeperPassword);
2181 if (!m_manager.StartGatekeeper())
2182 m_manager.Close();
2185 ////////////////////////////////////////
2186 // SIP fields
2187 config->SetPath(SIPGroup);
2188 SAVE_FIELD(SIPProxyUsed, m_manager.m_SIPProxyUsed =);
2189 m_manager.sipEP->SetProxy(m_SIPProxy, m_SIPProxyUsername, m_SIPProxyPassword);
2190 config->Write(SIPProxyKey, m_SIPProxy);
2191 config->Write(SIPProxyUsernameKey, m_SIPProxyUsername);
2192 config->Write(SIPProxyPasswordKey, m_SIPProxyPassword);
2194 config->Write(RegistrarTimeToLiveKey, m_RegistrarTimeToLive);
2195 m_manager.sipEP->SetRegistrarTimeToLive(PTimeInterval(0, m_RegistrarTimeToLive));
2197 if (m_manager.m_registrarUsed != m_RegistrarUsed ||
2198 m_manager.m_registrarName != m_RegistrarName ||
2199 m_manager.m_registrarUser != m_RegistrarUsername ||
2200 m_manager.m_registrarPassword != m_RegistrarPassword) {
2201 SAVE_FIELD(RegistrarUsed, m_manager.m_registrarUsed =);
2202 SAVE_FIELD(RegistrarName, m_manager.m_registrarName =);
2203 SAVE_FIELD(RegistrarUsername, m_manager.m_registrarUser =);
2204 SAVE_FIELD(RegistrarPassword, m_manager.m_registrarPassword =);
2205 m_manager.StartRegistrar();
2208 ////////////////////////////////////////
2209 // Routing fields
2212 #if PTRACING
2213 ////////////////////////////////////////
2214 // Tracing fields
2215 config->SetPath(TracingGroup);
2216 int traceOptions = 0;
2217 if (m_TraceLevelNumber)
2218 traceOptions |= PTrace::TraceLevel;
2219 if (m_TraceFileLine)
2220 traceOptions |= PTrace::FileAndLine;
2221 if (m_TraceBlocks)
2222 traceOptions |= PTrace::Blocks;
2223 if (m_TraceDateTime)
2224 traceOptions |= PTrace::DateAndTime;
2225 if (m_TraceTimestamp)
2226 traceOptions |= PTrace::Timestamp;
2227 if (m_TraceThreadName)
2228 traceOptions |= PTrace::Thread;
2229 if (m_TraceThreadAddress)
2230 traceOptions |= PTrace::ThreadAddress;
2232 config->Write(EnableTracingKey, m_EnableTracing);
2233 config->Write(TraceLevelThresholdKey, m_TraceLevelThreshold);
2234 config->Write(TraceFileNameKey, m_TraceFileName);
2235 config->Write(TraceOptionsKey, traceOptions);
2237 // Check for stopping tracing
2238 if (m_manager.m_enableTracing && (!m_EnableTracing || m_TraceFileName.empty()))
2239 PTrace::SetStream(NULL);
2240 else if (m_EnableTracing && (!m_manager.m_enableTracing || m_manager.m_traceFileName != m_TraceFileName))
2241 PTrace::Initialise(m_TraceLevelThreshold, m_TraceFileName, traceOptions);
2242 else {
2243 PTrace::SetLevel(m_TraceLevelThreshold);
2244 PTrace::SetOptions(traceOptions);
2245 PTrace::ClearOptions(~traceOptions);
2248 m_manager.m_enableTracing = m_EnableTracing;
2249 m_manager.m_traceFileName = m_TraceFileName;
2250 #endif // PTRACING
2252 ::wxEndBusyCursor();
2254 return true;
2258 ////////////////////////////////////////
2259 // General fields
2261 void OptionsDialog::BrowseSoundFile(wxCommandEvent & /*event*/)
2263 wxString newFile = wxFileSelector("Sound file to play on incoming calls",
2265 m_RingSoundFileName,
2266 ".wav",
2267 "WAV files (*.wav)|*.wav",
2268 wxOPEN|wxFILE_MUST_EXIST);
2269 if (!newFile.empty()) {
2270 m_RingSoundFileName = newFile;
2271 TransferDataToWindow();
2276 void OptionsDialog::PlaySoundFile(wxCommandEvent & /*event*/)
2278 PSoundChannel speaker(m_manager.m_RingSoundDeviceName, PSoundChannel::Player);
2279 speaker.PlayFile(m_RingSoundFileName.c_str());
2283 ////////////////////////////////////////
2284 // Networking fields
2286 void OptionsDialog::BandwidthClass(wxCommandEvent & event)
2288 static const char * bandwidthClasses[] = {
2289 "14.4", "28.8", "64.0", "128", "1500", "10000"
2292 m_Bandwidth = bandwidthClasses[event.GetSelection()];
2293 TransferDataToWindow();
2297 void OptionsDialog::SelectedLocalInterface(wxCommandEvent & /*event*/)
2299 m_RemoveInterface->Enable(m_LocalInterfaces->GetSelection() != wxNOT_FOUND);
2303 void OptionsDialog::ChangedInterfaceToAdd(wxCommandEvent & /*event*/)
2305 m_AddInterface->Enable(!m_InterfaceToAdd->GetValue().IsEmpty());
2309 void OptionsDialog::AddInterface(wxCommandEvent & /*event*/)
2311 m_LocalInterfaces->Append(m_InterfaceToAdd->GetValue());
2315 void OptionsDialog::RemoveInterface(wxCommandEvent & /*event*/)
2317 m_InterfaceToAdd->SetValue(m_LocalInterfaces->GetStringSelection());
2318 m_LocalInterfaces->Delete(m_LocalInterfaces->GetSelection());
2319 m_RemoveInterface->Disable();
2323 ////////////////////////////////////////
2324 // Audio fields
2326 void OptionsDialog::SelectedLID(wxCommandEvent & /*event*/)
2328 bool enabled = m_selectedLID->GetSelection() > 0;
2329 m_selectedAEC->Enable(enabled);
2330 m_selectedCountry->Enable(enabled);
2334 ////////////////////////////////////////
2335 // Codec fields
2337 void OptionsDialog::AddCodec(wxCommandEvent & /*event*/)
2339 int insertionPoint = -1;
2340 wxArrayInt destinationSelections;
2341 if (m_selectedCodecs->GetSelections(destinationSelections) > 0)
2342 insertionPoint = destinationSelections[0];
2344 wxArrayInt sourceSelections;
2345 m_allCodecs->GetSelections(sourceSelections);
2346 for (size_t i = 0; i < sourceSelections.GetCount(); i++) {
2347 int sourceSelection = sourceSelections[i];
2348 wxString value = m_allCodecs->GetString(sourceSelection);
2349 void * data = m_allCodecs->GetClientData(sourceSelection);
2350 value.Remove(0, value.Find(':')+2);
2351 if (m_selectedCodecs->FindString(value) < 0) {
2352 if (insertionPoint < 0)
2353 m_selectedCodecs->Append(value, data);
2354 else {
2355 m_selectedCodecs->InsertItems(1, &value, insertionPoint);
2356 m_selectedCodecs->SetClientData(insertionPoint, data);
2359 m_allCodecs->Deselect(sourceSelections[i]);
2362 m_AddCodec->Enable(false);
2366 void OptionsDialog::RemoveCodec(wxCommandEvent & /*event*/)
2368 wxArrayInt selections;
2369 m_selectedCodecs->GetSelections(selections);
2370 for (int i = selections.GetCount()-1; i >= 0; i--)
2371 m_selectedCodecs->Delete(selections[i]);
2372 m_RemoveCodec->Enable(false);
2373 m_MoveUpCodec->Enable(false);
2374 m_MoveDownCodec->Enable(false);
2378 void OptionsDialog::MoveUpCodec(wxCommandEvent & /*event*/)
2380 wxArrayInt selections;
2381 m_selectedCodecs->GetSelections(selections);
2382 wxString value = m_selectedCodecs->GetString(selections[0]);
2383 m_selectedCodecs->Delete(selections[0]);
2384 m_selectedCodecs->InsertItems(1, &value, selections[0]-1);
2385 m_selectedCodecs->SetSelection(selections[0]-1);
2386 m_MoveUpCodec->Enable(selections[0] > 1);
2387 m_MoveDownCodec->Enable(true);
2391 void OptionsDialog::MoveDownCodec(wxCommandEvent & /*event*/)
2393 wxArrayInt selections;
2394 m_selectedCodecs->GetSelections(selections);
2395 wxString value = m_selectedCodecs->GetString(selections[0]);
2396 m_selectedCodecs->Delete(selections[0]);
2397 m_selectedCodecs->InsertItems(1, &value, selections[0]+1);
2398 m_selectedCodecs->SetSelection(selections[0]+1);
2399 m_MoveUpCodec->Enable(true);
2400 m_MoveDownCodec->Enable(selections[0] < (int)m_selectedCodecs->GetCount()-2);
2404 void OptionsDialog::SelectedCodecToAdd(wxCommandEvent & /*event*/)
2406 wxArrayInt selections;
2407 m_AddCodec->Enable(m_allCodecs->GetSelections(selections) > 0);
2411 void OptionsDialog::SelectedCodec(wxCommandEvent & /*event*/)
2413 wxArrayInt selections;
2414 size_t count = m_selectedCodecs->GetSelections(selections);
2415 m_RemoveCodec->Enable(count > 0);
2416 m_MoveUpCodec->Enable(count == 1 && selections[0] > 0);
2417 m_MoveDownCodec->Enable(count == 1 && selections[0] < (int)m_selectedCodecs->GetCount()-1);
2419 m_codecOptions->DeleteAllItems();
2420 m_codecOptionValue->SetValue("");
2421 m_codecOptionValue->Disable();
2423 if (count == 1) {
2424 MyMedia * media = (MyMedia *)m_selectedCodecs->GetClientData(selections[0]);
2425 PAssert(media != NULL, PLogicError);
2426 for (PINDEX i = 0; i < media->mediaFormat.GetOptionCount(); i++) {
2427 const OpalMediaOption & option = media->mediaFormat.GetOption(i);
2428 wxListItem item;
2429 item.m_mask = wxLIST_MASK_TEXT|wxLIST_MASK_DATA;
2430 item.m_itemId = LONG_MAX;
2431 item.m_text = PwxString(option.GetName());
2432 item.m_data = option.IsReadOnly();
2433 long index = m_codecOptions->InsertItem(item);
2434 m_codecOptions->SetItem(index, 1, PwxString(option.AsString()));
2440 void OptionsDialog::SelectedCodecOption(wxListEvent & /*event*/)
2442 wxListItem item;
2443 item.m_mask = wxLIST_MASK_TEXT|wxLIST_MASK_DATA;
2444 item.m_itemId = m_codecOptions->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2445 item.m_col = 1;
2446 m_codecOptions->GetItem(item);
2447 m_codecOptionValue->Enable(!item.m_data);
2448 if (!item.m_data)
2449 m_codecOptionValue->SetValue(item.m_text);
2453 void OptionsDialog::DeselectedCodecOption(wxListEvent & /*event*/)
2455 m_codecOptionValue->SetValue("");
2456 m_codecOptionValue->Disable();
2460 void OptionsDialog::ChangedCodecOptionValue(wxCommandEvent & /*event*/)
2462 PwxString newValue = m_codecOptionValue->GetValue();
2464 wxListItem item;
2465 item.m_itemId = m_codecOptions->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2466 if (item.m_itemId < 0)
2467 return;
2469 item.m_mask = wxLIST_MASK_TEXT;
2470 item.m_col = 1;
2471 m_codecOptions->GetItem(item);
2473 if (item.m_text == newValue)
2474 return;
2476 item.m_text = newValue;
2477 m_codecOptions->SetItem(item);
2479 item.m_col = 0;
2480 m_codecOptions->GetItem(item);
2482 wxArrayInt selections;
2483 PAssert(m_selectedCodecs->GetSelections(selections) == 1, PLogicError);
2484 MyMedia * media = (MyMedia *)m_selectedCodecs->GetClientData(selections[0]);
2485 PAssert(media != NULL, PLogicError);
2486 if (media->mediaFormat.SetOptionValue(PwxString(item.m_text), newValue))
2487 media->dirty = true;
2488 else
2489 wxMessageBox("Could not set option to specified value!", "Error", wxCANCEL|wxICON_EXCLAMATION);
2493 ////////////////////////////////////////
2494 // H.323 fields
2496 void OptionsDialog::SelectedAlias(wxCommandEvent & /*event*/)
2498 m_RemoveAlias->Enable(m_Aliases->GetSelection() != wxNOT_FOUND);
2502 void OptionsDialog::ChangedNewAlias(wxCommandEvent & /*event*/)
2505 m_AddAlias->Enable(!m_NewAlias->GetValue().IsEmpty());
2509 void OptionsDialog::AddAlias(wxCommandEvent & /*event*/)
2511 m_Aliases->Append(m_NewAlias->GetValue());
2515 void OptionsDialog::RemoveAlias(wxCommandEvent & /*event*/)
2517 m_NewAlias->SetValue(m_Aliases->GetStringSelection());
2518 m_Aliases->Delete(m_Aliases->GetSelection());
2519 m_RemoveAlias->Disable();
2523 ////////////////////////////////////////
2524 // Routing fields
2526 void OptionsDialog::AddRoute(wxCommandEvent & /*event*/)
2528 int pos = m_Routes->InsertItem(m_SelectedRoute, m_RouteSource->GetValue());
2529 m_Routes->SetItem(pos, 1, m_RoutePattern->GetValue());
2530 m_Routes->SetItem(pos, 2, m_RouteDestination->GetValue());
2534 void OptionsDialog::RemoveRoute(wxCommandEvent & /*event*/)
2536 m_Routes->DeleteItem(m_SelectedRoute);
2540 void OptionsDialog::SelectedRoute(wxListEvent & event)
2542 m_SelectedRoute = event.GetIndex();
2543 m_RemoveRoute->Enable(true);
2547 void OptionsDialog::DeselectedRoute(wxListEvent & /*event*/)
2549 m_SelectedRoute = INT_MAX;
2550 m_RemoveRoute->Enable(false);
2554 void OptionsDialog::ChangedRouteInfo(wxCommandEvent & /*event*/)
2556 m_AddRoute->Enable(!m_RoutePattern->GetValue().IsEmpty() && !m_RouteDestination->GetValue().IsEmpty());
2560 ///////////////////////////////////////////////////////////////////////////////
2562 BEGIN_EVENT_TABLE(CallDialog, wxDialog)
2563 EVT_BUTTON(XRCID("wxID_OK"), CallDialog::OnOK)
2564 EVT_TEXT(XRCID("Address"), CallDialog::OnAddressChange)
2565 END_EVENT_TABLE()
2567 CallDialog::CallDialog(wxFrame * parent)
2569 wxXmlResource::Get()->LoadDialog(this, parent, "CallDialog");
2571 m_ok = FindWindowByNameAs<wxButton>(this, "wxID_OK");
2572 m_ok->Disable();
2574 m_AddressCtrl = FindWindowByNameAs<wxComboBox>(this, "Address");
2575 m_AddressCtrl->SetValidator(wxGenericValidator(&m_Address));
2577 wxConfigBase * config = wxConfig::Get();
2578 config->SetPath(RecentCallsGroup);
2579 wxString entryName;
2580 long entryIndex;
2581 if (config->GetFirstEntry(entryName, entryIndex)) {
2582 do {
2583 wxString address;
2584 if (config->Read(entryName, &address))
2585 m_AddressCtrl->AppendString(address);
2586 } while (config->GetNextEntry(entryName, entryIndex));
2591 void CallDialog::OnOK(wxCommandEvent & event)
2593 bool addNewEntry = true;
2595 wxConfigBase * config = wxConfig::Get();
2596 config->DeleteGroup(RecentCallsGroup);
2597 config->SetPath(RecentCallsGroup);
2599 size_t index;
2600 for (index = 0; index < m_AddressCtrl->GetCount(); ++index) {
2601 wxString entry = m_AddressCtrl->GetString(index);
2603 wxString key;
2604 key.sprintf("%u", index+1);
2605 config->Write(key, entry);
2607 if (m_Address == entry)
2608 addNewEntry = false;
2610 if (index >= MaxSavedRecentCalls-(addNewEntry?1:0))
2611 break;
2614 if (addNewEntry) {
2615 wxString key;
2616 key.sprintf("%u", index+1);
2617 config->Write(key, m_Address);
2622 void CallDialog::OnAddressChange(wxCommandEvent & WXUNUSED(event))
2624 TransferDataFromWindow();
2625 m_ok->Enable(!m_Address.IsEmpty());
2629 ///////////////////////////////////////////////////////////////////////////////
2631 BEGIN_EVENT_TABLE(AnswerPanel, wxPanel)
2632 EVT_BUTTON(XRCID("AnswerCall"), AnswerPanel::OnAnswer)
2633 EVT_BUTTON(XRCID("RejectCall"), AnswerPanel::OnReject)
2634 END_EVENT_TABLE()
2636 AnswerPanel::AnswerPanel(MyManager & manager, wxWindow * parent)
2637 : m_manager(manager)
2639 wxXmlResource::Get()->LoadPanel(this, parent, "AnswerPanel");
2643 void AnswerPanel::OnAnswer(wxCommandEvent & /*event*/)
2645 m_manager.AnswerCall();
2649 void AnswerPanel::OnReject(wxCommandEvent & /*event*/)
2651 m_manager.RejectCall();
2655 ///////////////////////////////////////////////////////////////////////////////
2657 BEGIN_EVENT_TABLE(CallingPanel, wxPanel)
2658 EVT_BUTTON(XRCID("HangUpCall"), CallingPanel::OnHangUp)
2659 END_EVENT_TABLE()
2661 CallingPanel::CallingPanel(MyManager & manager, wxWindow * parent)
2662 : m_manager(manager)
2664 wxXmlResource::Get()->LoadPanel(this, parent, "CallingPanel");
2668 void CallingPanel::OnHangUp(wxCommandEvent & /*event*/)
2670 m_manager.HangUpCall();
2674 ///////////////////////////////////////////////////////////////////////////////
2676 const int VU_UPDATE_TIMER_ID = 1000;
2678 BEGIN_EVENT_TABLE(InCallPanel, wxPanel)
2679 EVT_BUTTON(XRCID("HangUp"), InCallPanel::OnHangUp)
2680 EVT_BUTTON(XRCID("Input1"), InCallPanel::OnUserInput1)
2681 EVT_BUTTON(XRCID("Input2"), InCallPanel::OnUserInput2)
2682 EVT_BUTTON(XRCID("Input3"), InCallPanel::OnUserInput3)
2683 EVT_BUTTON(XRCID("Input4"), InCallPanel::OnUserInput4)
2684 EVT_BUTTON(XRCID("Input5"), InCallPanel::OnUserInput5)
2685 EVT_BUTTON(XRCID("Input6"), InCallPanel::OnUserInput6)
2686 EVT_BUTTON(XRCID("Input7"), InCallPanel::OnUserInput7)
2687 EVT_BUTTON(XRCID("Input8"), InCallPanel::OnUserInput8)
2688 EVT_BUTTON(XRCID("Input9"), InCallPanel::OnUserInput9)
2689 EVT_BUTTON(XRCID("Input0"), InCallPanel::OnUserInput0)
2690 EVT_BUTTON(XRCID("InputStar"), InCallPanel::OnUserInputStar)
2691 EVT_BUTTON(XRCID("InputHash"), InCallPanel::OnUserInputHash)
2692 EVT_BUTTON(XRCID("InputFlash"), InCallPanel::OnUserInputFlash)
2694 EVT_COMMAND_SCROLL(XRCID("SpeakerVolume"), InCallPanel::SpeakerVolume)
2695 EVT_COMMAND_SCROLL(XRCID("MicrophoneVolume"), InCallPanel::MicrophoneVolume)
2697 EVT_TIMER(VU_UPDATE_TIMER_ID, InCallPanel::OnUpdateVU)
2698 END_EVENT_TABLE()
2700 InCallPanel::InCallPanel(MyManager & manager, wxWindow * parent)
2701 : m_manager(manager)
2702 , m_vuTimer(this, VU_UPDATE_TIMER_ID)
2704 wxXmlResource::Get()->LoadPanel(this, parent, "InCallPanel");
2706 m_SpeakerVolume = FindWindowByNameAs<wxSlider>(this, "SpeakerVolume");
2707 m_MicrophoneVolume = FindWindowByNameAs<wxSlider>(this, "MicrophoneVolume");
2708 m_vuSpeaker = FindWindowByNameAs<wxGauge>(this, "SpeakerGauge");
2709 m_vuMicrophone = FindWindowByNameAs<wxGauge>(this, "MicrophoneGauge");
2711 m_FirstTime = true;
2715 bool InCallPanel::Show(bool show)
2717 wxConfigBase * config = wxConfig::Get();
2718 config->SetPath(AudioGroup);
2720 if (show || m_FirstTime) {
2721 m_FirstTime = false;
2723 int value = 50;
2724 config->Read(SpeakerVolumeKey, &value);
2725 m_SpeakerVolume->SetValue(value);
2726 SetVolume(false, value);
2728 value = 50;
2729 config->Read(MicrophoneVolumeKey, &value);
2730 m_MicrophoneVolume->SetValue(value);
2731 SetVolume(true, value);
2733 if (show)
2734 m_vuTimer.Start(250);
2736 else {
2737 config->Write(SpeakerVolumeKey, m_SpeakerVolume->GetValue());
2738 config->Write(MicrophoneVolumeKey, m_MicrophoneVolume->GetValue());
2740 m_vuTimer.Stop();
2743 return wxPanel::Show(show);
2747 void InCallPanel::OnHangUp(wxCommandEvent & /*event*/)
2749 m_manager.HangUpCall();
2752 #define ON_USER_INPUT_HANDLER(i,c) \
2753 void InCallPanel::OnUserInput##i(wxCommandEvent &) \
2754 { m_manager.SendUserInput(c); }
2756 ON_USER_INPUT_HANDLER(1,'1')
2757 ON_USER_INPUT_HANDLER(2,'2')
2758 ON_USER_INPUT_HANDLER(3,'3')
2759 ON_USER_INPUT_HANDLER(4,'4')
2760 ON_USER_INPUT_HANDLER(5,'5')
2761 ON_USER_INPUT_HANDLER(6,'6')
2762 ON_USER_INPUT_HANDLER(7,'7')
2763 ON_USER_INPUT_HANDLER(8,'8')
2764 ON_USER_INPUT_HANDLER(9,'9')
2765 ON_USER_INPUT_HANDLER(0,'0')
2766 ON_USER_INPUT_HANDLER(Star,'*')
2767 ON_USER_INPUT_HANDLER(Hash,'#')
2768 ON_USER_INPUT_HANDLER(Flash,'!')
2771 void InCallPanel::SpeakerVolume(wxScrollEvent & event)
2773 SetVolume(false, event.GetPosition());
2777 void InCallPanel::MicrophoneVolume(wxScrollEvent & event)
2779 SetVolume(true, event.GetPosition());
2783 void InCallPanel::SetVolume(bool isMicrophone, int value)
2785 PSafePtr<OpalConnection> connection = m_manager.GetUserConnection();
2786 if (connection != NULL)
2787 connection->SetAudioVolume(isMicrophone, value);
2791 static void SetGauge(wxGauge * gauge, int level)
2793 if (level < 0 || level > 32767) {
2794 gauge->Show(false);
2795 return;
2797 gauge->Show();
2798 gauge->SetValue((int)(log10(9.0*level/32768.0+1)*100)); // Convert to logarithmic scale
2802 void InCallPanel::OnUpdateVU(wxTimerEvent& event)
2804 int micLevel = -1;
2805 int spkLevel = -1;
2806 PSafePtr<OpalConnection> connection = m_manager.GetUserConnection();
2807 if (connection != NULL) {
2808 spkLevel = connection->GetAudioSignalLevel(false);
2809 micLevel = connection->GetAudioSignalLevel(true);
2812 SetGauge(m_vuSpeaker, spkLevel);
2813 SetGauge(m_vuMicrophone, micLevel);
2817 ///////////////////////////////////////////////////////////////////////////////
2819 BEGIN_EVENT_TABLE(SpeedDialDialog, wxDialog)
2820 EVT_TEXT(XRCID("SpeedDialName"), SpeedDialDialog::OnChange)
2821 EVT_TEXT(XRCID("SpeedDialNumber"), SpeedDialDialog::OnChange)
2822 END_EVENT_TABLE()
2824 SpeedDialDialog::SpeedDialDialog(MyManager * manager)
2825 : m_manager(*manager)
2827 wxXmlResource::Get()->LoadDialog(this, manager, "SpeedDialDialog");
2829 m_ok = FindWindowByNameAs<wxButton>(this, "wxID_OK");
2831 m_nameCtrl = FindWindowByNameAs<wxTextCtrl>(this, "SpeedDialName");
2832 m_nameCtrl->SetValidator(wxGenericValidator(&m_Name));
2834 m_numberCtrl = FindWindowByNameAs<wxTextCtrl>(this, "SpeedDialNumber");
2835 m_numberCtrl->SetValidator(wxGenericValidator(&m_Number));
2837 FindWindowByName("SpeedDialAddress")->SetValidator(wxGenericValidator(&m_Address));
2838 FindWindowByName("SpeedDialDescription")->SetValidator(wxGenericValidator(&m_Description));
2840 m_inUse = FindWindowByNameAs<wxStaticText>(this, "SpeedDialInUse");
2841 m_ambiguous = FindWindowByNameAs<wxStaticText>(this, "SpeedDialAmbiguous");
2845 void SpeedDialDialog::OnChange(wxCommandEvent & WXUNUSED(event))
2847 wxString newName = m_nameCtrl->GetValue();
2848 bool inUse = newName != m_Name && m_manager.HasSpeedDialName(newName);
2849 m_inUse->Show(inUse);
2851 m_ok->Enable(!newName.IsEmpty() && !inUse);
2853 m_ambiguous->Show(m_manager.GetSpeedDialIndex(m_numberCtrl->GetValue(), m_Number) >= 0);
2857 ///////////////////////////////////////////////////////////////////////////////
2859 MyPCSSEndPoint::MyPCSSEndPoint(MyManager & manager)
2860 : OpalPCSSEndPoint(manager),
2861 m_manager(manager)
2866 BOOL MyPCSSEndPoint::OnShowIncoming(const OpalPCSSConnection & connection)
2868 m_manager.OnRinging(connection);
2869 return TRUE;
2874 BOOL MyPCSSEndPoint::OnShowOutgoing(const OpalPCSSConnection & connection)
2876 PTime now;
2877 LogWindow << connection.GetRemotePartyName() << " is ringing on "
2878 << now.AsString("w h:mma") << " ..." << endl;
2879 return TRUE;
2883 ///////////////////////////////////////////////////////////////////////////////
2884 #if OPAL_H323
2886 MyH323EndPoint::MyH323EndPoint(MyManager & manager)
2887 : H323EndPoint(manager),
2888 m_manager(manager)
2893 void MyH323EndPoint::OnRegistrationConfirm()
2895 // LogWindow << "H.323 registration successful." << endl;
2898 #endif
2901 ///////////////////////////////////////////////////////////////////////////////
2902 #if OPAL_SIP
2904 MySIPEndPoint::MySIPEndPoint(MyManager & manager)
2905 : SIPEndPoint(manager),
2906 m_manager(manager)
2911 void MySIPEndPoint::OnRegistered()
2913 LogWindow << "SIP registration successful." << endl;
2916 #endif
2919 // End of File ///////////////////////////////////////////////////////////////