main.cxx
上传用户:sdyzjx
上传日期:2007-01-06
资源大小:47k
文件大小:86k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * main.cxx
  3.  *
  4.  * PWLib application source file for OpenPhone
  5.  *
  6.  * Open H323 Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Open H323 Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions of this code were written with the assisance of funding from
  25.  * Vovida Networks, Inc. http://www.vovida.com.
  26.  *
  27.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  28.  * All Rights Reserved.
  29.  *
  30.  * Contributor(s): Portions Copyright 1999 NEWLINK
  31.  *
  32.  * $Log: main.cxx,v $
  33.  * Revision 1.87  2000/07/15 09:48:49  robertj
  34.  * Added message for unregistering from gatekeeper.
  35.  *
  36.  * Revision 1.86  2000/07/13 15:49:52  robertj
  37.  * Renamed all codecs so obvious whether software or hardware.
  38.  * Split autoStartVideo so can select receive and transmit independently
  39.  * Fixed the previous fix in the most recent calls list.
  40.  * Added frame count to message on audio channel open.
  41.  *
  42.  * Revision 1.85  2000/07/11 19:54:47  robertj
  43.  * Fixed crash if closed speed dial window while handset off hook.
  44.  * Fixed recent call list so saves recent calls now.
  45.  * Added ability to set the frames per packet in audio codecs.
  46.  * Added correct insertion of H.261 capabilities for on the fly qcif/cif switching.
  47.  *
  48.  * Revision 1.84  2000/07/09 14:51:17  robertj
  49.  * Fixed incorrect colours in video display window.
  50.  *
  51.  * Revision 1.83  2000/07/02 09:14:09  robertj
  52.  * Fixed problems with closing video receive window under Win32.
  53.  *
  54.  * Revision 1.82  2000/06/29 11:00:04  robertj
  55.  * Added user interface for sound buffer depth adjustment.
  56.  *
  57.  * Revision 1.81  2000/06/29 06:20:53  robertj
  58.  * Fixed deadlock when exiting application while in a call.
  59.  *
  60.  * Revision 1.80  2000/06/20 12:51:23  robertj
  61.  * Changed IXJ driver open so does not change selected line to PSTN.
  62.  *
  63.  * Revision 1.79  2000/06/20 03:18:05  robertj
  64.  * Added function to get name of gatekeeper, subtle difference from getting identifier.
  65.  *
  66.  * Revision 1.78  2000/06/20 02:38:28  robertj
  67.  * Changed H323TransportAddress to default to IP.
  68.  *
  69.  * Revision 1.77  2000/06/19 00:32:22  robertj
  70.  * Changed functionf or adding all lid capabilities to not assume it is to an endpoint.
  71.  *
  72.  * Revision 1.76  2000/06/15 01:46:15  robertj
  73.  * Added channel pause (aka mute) functions.
  74.  *
  75.  * Revision 1.75  2000/06/09 07:50:11  robertj
  76.  * Changed PSTN line psuedo gateway to use LID Dial function.
  77.  *
  78.  * Revision 1.74  2000/06/07 05:48:06  robertj
  79.  * Added call forwarding.
  80.  *
  81.  * Revision 1.73  2000/06/05 04:45:12  robertj
  82.  * Added LPC-10 2400bps codec
  83.  *
  84.  * Revision 1.72  2000/05/30 10:19:28  robertj
  85.  * Added function to add capabilities given a LID.
  86.  * Improved LID capabilities so cannot create one that is not explicitly supported.
  87.  *
  88.  * Revision 1.71  2000/05/23 12:57:37  robertj
  89.  * Added ability to change IP Type Of Service code from applications.
  90.  *
  91.  * Revision 1.70  2000/05/23 11:32:37  robertj
  92.  * Rewrite of capability table to combine 2 structures into one and move functionality into that class
  93.  *    allowing some normalisation of usage across several applications.
  94.  * Changed H323Connection so gets a copy of capabilities instead of using endponts, allows adjustments
  95.  *    to be done depending on the remote client application.
  96.  *
  97.  * Revision 1.69  2000/05/16 08:23:34  robertj
  98.  * Added ability to change silence detect mode on active call.
  99.  *
  100.  * Revision 1.68  2000/05/10 05:16:00  robertj
  101.  * Added hook flash to user indications. Also allowed selection of the User Indication
  102.  *    method to be used in the H.245 protocol.
  103.  *
  104.  * Revision 1.67  2000/05/10 04:06:19  robertj
  105.  * Added ability to disable an audio codec as well as change its priority.
  106.  *
  107.  * Revision 1.66  2000/05/05 03:45:05  robertj
  108.  * Added ability to set multiple aliases for endpoint.
  109.  * Added "bandwidth by type" so can specify by saying "T1" for example.
  110.  *
  111.  * Revision 1.65  2000/05/04 11:53:38  robertj
  112.  * Added Packets Too Late statistics.
  113.  * Fixed gatekeeper detection so if "required", disables call menus.
  114.  *
  115.  * Revision 1.64  2000/05/01 13:00:29  robertj
  116.  * Changed SetCapability() to append capabilities to TCS, helps with assuring no gaps in set.
  117.  *
  118.  * Revision 1.63  2000/05/01 08:20:28  robertj
  119.  * Fixed capability loading so do not need to restart program when altering video parameters.
  120.  *
  121.  * Revision 1.62  2000/04/19 02:07:29  robertj
  122.  * Fixed problems with video window.
  123.  *
  124.  * Revision 1.61  2000/04/14 21:48:49  robertj
  125.  * Fixed gatekeeper search default value to OFF.
  126.  *
  127.  * Revision 1.60  2000/04/13 00:14:25  robertj
  128.  * Fixed display of correct ixj card in drop down box on first time use.
  129.  * Changed default gatekeeper detection to OFF.
  130.  *
  131.  * Revision 1.59  2000/04/11 03:59:33  robertj
  132.  * Added new call end reasons for gatekeeper denied calls.
  133.  *
  134.  * Revision 1.58  2000/04/06 19:59:56  robertj
  135.  * Used named constants instead of literals for xJack line selection.
  136.  *
  137.  * Revision 1.57  2000/04/06 17:38:52  robertj
  138.  * Fixed ability to change Quicknet card without restarting program.
  139.  *
  140.  * Revision 1.56  2000/04/05 20:56:47  robertj
  141.  * Added more statistics.
  142.  *
  143.  * Revision 1.55  2000/04/04 20:37:10  robertj
  144.  * Fixed inability to set discovery mode in dialog, thanks Thien Nguyen.
  145.  *
  146.  * Revision 1.54  2000/03/30 19:57:58  robertj
  147.  * Fixed some call end message strings, also added cap exchange failure message.
  148.  * Added G.728/G.729 support via new LID GetPayloadTypes() function.
  149.  * Fixed possible deadlock exiting application with active call (Win32 only).
  150.  *
  151.  * Revision 1.53  2000/03/21 03:06:48  robertj
  152.  * Changes to make RTP TX of exact numbers of frames in some codecs.
  153.  *
  154.  * Revision 1.52  2000/03/20 20:30:09  robertj
  155.  * Usability improvement, hide speed dial dialog so can see dial progress.
  156.  *
  157.  * Revision 1.51  2000/03/04 13:44:00  robertj
  158.  * Added timer to ring every 5 seconds and not just once!
  159.  *
  160.  * Revision 1.50  2000/03/04 12:16:55  robertj
  161.  * Added ring sound file to standard sound device on incoming calls.
  162.  *
  163.  * Revision 1.49  2000/02/29 12:58:27  robertj
  164.  * Added extra tracing options to dialog.
  165.  *
  166.  * Revision 1.48  2000/02/17 12:25:16  robertj
  167.  * Added user indication send/receive and option to disable H.245 tunneling.
  168.  *
  169.  * Revision 1.47  2000/02/16 05:21:39  robertj
  170.  * Added dialog parametes for vide transmission, still no grabber yet.
  171.  *
  172.  * Revision 1.46  2000/02/16 03:32:47  robertj
  173.  * Fixed bug where selecting previous address in make call dialog, didn't use gateway.
  174.  *
  175.  * Revision 1.45  2000/01/20 07:55:12  robertj
  176.  * Fixed shutdown bug locking up if Quicknet card used.
  177.  *
  178.  * Revision 1.44  2000/01/07 08:28:09  robertj
  179.  * Additions and changes to line interface device base class.
  180.  *
  181.  * Revision 1.43  1999/12/31 00:05:06  robertj
  182.  * Added Microsoft ACM G.723.1 Codec capability.
  183.  *
  184.  * Revision 1.42  1999/12/23 23:02:35  robertj
  185.  * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
  186.  *
  187.  * Revision 1.41  1999/11/29 04:50:11  robertj
  188.  * Added adaptive threshold calculation to silence detection.
  189.  *
  190.  * Revision 1.40  1999/11/23 11:09:43  robertj
  191.  * Fixed speakerphone state reset and uninitialised speakerphone flag variable.
  192.  *
  193.  * Revision 1.39  1999/11/22 13:32:19  robertj
  194.  * Added more calling tones.
  195.  *
  196.  * Revision 1.38  1999/11/22 11:20:47  robertj
  197.  * Fixed problem with handset pick up while making H.323 call but before connected.
  198.  *
  199.  * Revision 1.37  1999/11/22 10:07:23  robertj
  200.  * Fixed some errors in correct termination states.
  201.  *
  202.  * Revision 1.36  1999/11/22 00:56:34  robertj
  203.  * Improved reason display for connection failure.
  204.  *
  205.  * Revision 1.35  1999/11/20 00:30:02  robertj
  206.  * Fixed incorrect call mode when replacing up handset after outside line call.
  207.  *
  208.  * Revision 1.34  1999/11/19 13:00:52  robertj
  209.  * Added HangingUp state so can't start new call till old one fully cleared.
  210.  *
  211.  * Revision 1.33  1999/11/19 09:41:54  robertj
  212.  * Fixed decimals on call duration string.
  213.  *
  214.  * Revision 1.32  1999/11/19 09:16:04  robertj
  215.  * Added some times for call start and duration, reduced default jitter and removed G729/729.
  216.  *
  217.  * Revision 1.31  1999/11/18 12:50:49  robertj
  218.  * Fixed ring cadence value.
  219.  *
  220.  * Revision 1.30  1999/11/17 03:49:51  robertj
  221.  * Added RTP statistics display.
  222.  *
  223.  * Revision 1.29  1999/11/16 13:22:24  robertj
  224.  * Improved versioning in about dialog (version number now in single place)
  225.  *
  226.  * Revision 1.28  1999/11/16 11:32:06  robertj
  227.  * Added some calling tones.
  228.  *
  229.  * Revision 1.27  1999/11/13 14:13:08  robertj
  230.  * Changes to make silence detection selectable, disable quicknet option if no cards and fixed some UI errors.
  231.  *
  232.  * Revision 1.26  1999/11/11 23:35:45  robertj
  233.  * Fixed GCC warnings
  234.  *
  235.  * Revision 1.25  1999/11/11 23:14:40  robertj
  236.  * Fixed turning off ring on answering call and disabling call menu if initialisation failed.
  237.  *
  238.  * Revision 1.24  1999/11/11 08:54:27  robertj
  239.  * Changed preferred codec function to be full codec ordering.
  240.  *
  241.  * Revision 1.23  1999/11/11 01:20:48  robertj
  242.  * Numerous enhancements to get nearly feature complete for version 1.
  243.  *
  244.  * Revision 1.22  1999/11/06 03:48:36  robertj
  245.  * Added shells for mute functions
  246.  *
  247.  * Revision 1.21  1999/11/05 10:51:17  robertj
  248.  * Fixed problem with new ixj channel doing incorrect double initialise
  249.  *
  250.  * Revision 1.20  1999/11/05 08:54:41  robertj
  251.  * Rewrite of ixj interface code to fix support for arbitrary codecs.
  252.  *
  253.  * Revision 1.19  1999/11/01 00:50:16  robertj
  254.  * Added receive H.261 video window
  255.  *
  256.  * Revision 1.18  1999/10/30 13:44:03  robertj
  257.  * Fixed duplicate ID in resource strings.
  258.  *
  259.  * Revision 1.17  1999/10/30 12:45:47  robertj
  260.  * Added stop channel message, outside line message and G728/G729 interlock for LineJACK
  261.  *
  262.  * Revision 1.16  1999/10/29 12:09:14  robertj
  263.  * Fixed compiling no trace version.
  264.  *
  265.  * Revision 1.15  1999/10/29 02:28:24  robertj
  266.  * Fixed unix compatibility problem.
  267.  *
  268.  * Revision 1.14  1999/10/29 02:26:52  robertj
  269.  * Added scrollable status window and better termination information.
  270.  *
  271.  * Revision 1.13  1999/10/28 12:21:34  robertj
  272.  * Added AEC support and speakerphone switching button.
  273.  *
  274.  * Revision 1.12  1999/10/27 06:32:50  robertj
  275.  * Changes to prevent H225 alerting message being sent if "engaged".
  276.  *
  277.  * Revision 1.11  1999/10/24 15:29:53  robertj
  278.  * Fixed warning on NoTrace build
  279.  *
  280.  * Revision 1.10  1999/10/24 14:44:00  robertj
  281.  * Removed EnableDetectDTMF() as unix ioctl does not exist.
  282.  *
  283.  * Revision 1.9  1999/10/24 14:20:11  robertj
  284.  * Fixed GCC compatibility
  285.  *
  286.  * Revision 1.8  1999/10/24 12:59:40  robertj
  287.  * Added platform independent support for Quicknet xJACK cards.
  288.  *
  289.  * Revision 1.7  1999/10/09 04:19:30  robertj
  290.  * Fixed error passing PString as ... parameter, needs (const char *) cast
  291.  *
  292.  * Revision 1.6  1999/10/08 00:28:21  robertj
  293.  * Fixed some bugs in trace dialog
  294.  *
  295.  * Revision 1.5  1999/10/07 07:37:31  robertj
  296.  * Added auto-answer and trace options (thanks David Iodice of NEWLINK)
  297.  *
  298.  * Revision 1.4  1999/09/25 00:25:39  robertj
  299.  * Used new, neater, capability addition code.
  300.  *
  301.  * Revision 1.3  1999/09/09 01:09:46  robertj
  302.  * Added support for video capabilities & codec, still needs the actual codec itself!
  303.  *
  304.  * Revision 1.2  1999/09/01 06:12:21  robertj
  305.  * Added gatekeeper support.
  306.  *
  307.  * Revision 1.1  1999/08/25 05:16:11  robertj
  308.  * GUI test application.
  309.  *
  310.  * Revision 1.2  1999/01/26 06:35:07  robertj
  311.  * Fixed $LOG$ variable in template files
  312.  *
  313.  */
  314. #include <pwlib.h>
  315. #include "main.h"
  316. #include "version.h"
  317. #if PTRACING
  318. #include "resources.h"
  319. #else
  320. #include "resources_notrace.h"
  321. #endif
  322. #include "gsmcodec.h"
  323. #include "lpc10codec.h"
  324. #include "h261codec.h"
  325. #ifdef WIN32
  326. #include "acmcodec.h"
  327. #endif
  328. #define ENABLE_TRANSMITTER 1 // Clear to temporarily disable the transmitter start up
  329. #define ENABLE_RECEIVER    1 // Clear to temporarily disable the receiver acceptance
  330. PCREATE_PROCESS(OpenPhone);
  331. const char CodecsConfigSection[] = "Codecs";
  332. const char RecentCallsConfigSection[] = "Recent Calls";
  333. const char SpeedDialConfigSection[] = "Speed Dial";
  334. const char MainWindowTopConfigKey[] = "MainWindowTop";
  335. const char MainWindowLeftConfigKey[] = "MainWindowLeft";
  336. const char MainWindowWidthConfigKey[] = "MainWindowWidth";
  337. const char MainWindowHeightConfigKey[] = "MainWindowHeight";
  338. const char LocalVideoWindowTopConfigKey[] = "LocalVideoWindowTop";
  339. const char LocalVideoWindowLeftConfigKey[] = "LocalVideoWindowLeft";
  340. const char RemoteVideoWindowTopConfigKey[] = "RemoteVideoWindowTop";
  341. const char RemoteVideoWindowLeftConfigKey[] = "RemoteVideoWindowLeft";
  342. const char AutoAnswerConfigKey[] = "AutoAnswer";
  343. const char DtmfAsStringConfigKey[] = "DtmfAsString";
  344. const char SilenceDetectConfigKey[] = "SilenceDetect";
  345. const char NoFastStartConfigKey[] = "NoFastStart";
  346. const char NoTunnelingConfigKey[] = "NoTunneling";
  347. const char MaxRecentCallsConfigKey[] = "MaxRecentCalls";
  348. const char IpTosConfigKey[] = "IpTOS";
  349. const char UsernameConfigKey[] = "Username";
  350. const char AliasConfigKey[] = "Alias %u";
  351. const char AlwaysForwardPartyConfigKey[] = "AlwaysForwardParty";
  352. const char BusyForwardPartyConfigKey[] = "BusyForwardParty";
  353. const char NoAnswerForwardPartyConfigKey[] = "NoAnswerForwardParty";
  354. const char NoAnswerTimeConfigKey[] = "NoAnswerTime";
  355. const char RingSoundFileConfigKey[] = "RingSoundFile";
  356. const char SoundBuffersConfigKey[] = "SoundBuffers";
  357. const char AECConfigKey[] = "AEC";
  358. const char JitterConfigKey[] = "Jitter";
  359. const char BandwidthTypeConfigKey[] = "BandwidthType";
  360. const char BandwidthConfigKey[] = "Bandwidth";
  361. const char UseGatekeeperConfigKey[] = "UseGatekeeper";
  362. const char RequireGatekeeperConfigKey[] = "RequireGatekeeper";
  363. const char GatekeeperHostConfigKey[] = "GatekeeperHost";
  364. const char SoundPlayConfigKey[] = "SoundPlayDevice";
  365. const char SoundRecordConfigKey[] = "SoundRecordDevice";
  366. const char SpeakerVolumeConfigKey[] = "SpeakerVolume";
  367. const char MicrophoneVolumeConfigKey[] = "MicrophoneVolume";
  368. const char UseQuicknetConfigKey[] = "UseQuicknet";
  369. const char QuicknetDeviceConfigKey[] = "QuicknetDevice";
  370. const char H261QCIFConfigKey[] = "H261_QCIF";
  371. const char H261CIFConfigKey[] = "H261_CIF";
  372. const char AutoReceiveVideoConfigKey[] = "AutoReceiveVideo";
  373. const char VideoSizeConfigKey[] = "VideoSize";
  374. const char VideoSourceConfigKey[] = "VideoSource";
  375. const char VideoFormatConfigKey[] = "VideoFormat";
  376. const char VideoQualityConfigKey[] = "VideoQuality";
  377. #if PTRACING
  378. const char TraceFileConfigKey[] = "TraceFile";
  379. const char TraceLevelConfigKey[] = "TraceLevel";
  380. const char TraceBlockConfigKey[] = "TraceBlocks";
  381. const char TraceDateTimeConfigKey[] = "TraceDateAndTime";
  382. const char TraceTimestampConfigKey[] = "TraceTimestamp";
  383. const char TraceThreadsConfigKey[] = "TraceThreads";
  384. const char TraceThreadAddresssConfigKey[] = "TraceThreadAddresss";
  385. const char TraceLevelDisplayConfigKey[] = "TraceLevelDisplay";
  386. const char TraceFileLineConfigKey[] = "TraceFileAndLine";
  387. #endif
  388. const char InternalGatewayName[] = "<<Local-PSTN>>";
  389. const char CodecsConfigKey[] = "Codec%u";
  390. const char OnCodecSuffix[] = " (On)";
  391. const char OffCodecSuffix[] = " (Off)";
  392. const DWORD RingCadence = 0x145;  // 0001 0100 0101
  393. const PDIMENSION StatusWindowHeight = 25;
  394. const PDIMENSION CallButtonHeight = 15;
  395. const PDIMENSION ScrollBarHeight = 12;
  396. const PDIMENSION SpeedDialButtonHeight = 12;
  397. #define new PNEW
  398. ///////////////////////////////////////////////////////////////////////////////
  399. OpenPhone::OpenPhone()
  400.   : PApplication("Equivalence", "OpenPhone",
  401.                  MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
  402. {
  403. }
  404. void OpenPhone::Main()
  405. {
  406.   // create the main window and endpoint
  407.   new MainWindow(GetArguments());
  408.   // enter the main loop
  409.   PApplication::Main();
  410. }
  411. void OpenPhone::OnAbout()
  412. {
  413.   AboutDialog dlg(mainWindow);
  414.   dlg.version->SetName(dlg.version->GetName() + GetVersion(TRUE));
  415.   dlg.RunModal();
  416. }
  417. ///////////////////////////////////////////////////////////////////////////////
  418. MainWindow::MainWindow(PArgList & /*args*/)
  419. #ifdef _MSC_VER
  420. #pragma warning(disable:4355)
  421. #endif
  422.   : endpoint(this)
  423. #ifdef _MSC_VER
  424. #pragma warning(default:4355)
  425. #endif
  426. {
  427.   PConfig config;
  428. #if PTRACING
  429.   myTraceFile = NULL;
  430.   OpenTraceFile(config);
  431. #endif
  432.   SetTitle(PResourceString(IDS_TITLE));
  433.   SetIcon(PIcon(IDI_MAIN_WINDOW));
  434.   myMainMenu = new MainMenu(this);
  435.   SetMenu(myMainMenu);        
  436.   // set the background colour and load the image
  437.   SetBackgroundColour(PColour::Grey);
  438.   // set the minimum window size
  439.   SetMinSize(150, 50, LocalCoords);
  440.   // Set remembered position of main window
  441.   PPoint pos(config.GetInteger(MainWindowLeftConfigKey, INT_MAX),
  442.              config.GetInteger(MainWindowTopConfigKey, INT_MAX));
  443.   if (pos != PPoint(INT_MAX, INT_MAX))
  444.     SetPosition(pos, TopLeftPixels, TopLeftPixels);
  445.   PDim dim(config.GetInteger(MainWindowWidthConfigKey, 0),
  446.            config.GetInteger(MainWindowHeightConfigKey, 0));
  447.   if (dim != PDim(0, 0))
  448.     SetDimensions(dim, PixelCoords);
  449.   else
  450.     SetDimensions(160, StatusWindowHeight +
  451.                        CallButtonHeight +
  452.                        ScrollBarHeight +
  453.                        SpeedDialButtonHeight,
  454.                   LocalCoords);
  455.   dim = GetDimensions(LocalCoords);
  456.   // create status window
  457.   statusWindow = new PStringListBox(this, PListBox::NotSorted);
  458.   statusWindow->SetDimensions(dim.Width(), StatusWindowHeight, LocalCoords);
  459.   statusWindow->SetPosition(0, 0);
  460.   statusWindow->SetBackgroundColour(PColour::Black);
  461.   statusWindow->SetForegroundColour(PColour::Green);
  462.   statusWindow->Show();
  463.   answerButton = new PTextButton(this, PResourceString(IDS_ANSWERCALL), PCREATE_NOTIFIER(OnAnswerButton));
  464.   answerButton->SetDimensions(dim.Width()/2, CallButtonHeight, LocalCoords);
  465.   answerButton->SetPosition(0, StatusWindowHeight);
  466.   refuseButton = new PTextButton(this, PResourceString(IDS_REFUSECALL), PCREATE_NOTIFIER(OnRefuseButton));
  467.   refuseButton->SetDimensions(dim.Width()/2, CallButtonHeight, LocalCoords);
  468.   refuseButton->SetPosition(dim.Width()/2, StatusWindowHeight);
  469.   hangUpButton = new PTextButton(this, PResourceString(IDS_HANGUP), PCREATE_NOTIFIER(OnHangUpButton));
  470.   hangUpButton->SetDimensions(dim.Width()/2, CallButtonHeight, LocalCoords);
  471.   hangUpButton->SetPosition(0, StatusWindowHeight);
  472.   speakerButton = new PTextButton(this, PResourceString(IDS_SPEAKERPHONE), PCREATE_NOTIFIER(OnSpeakerButton));
  473.   speakerButton->SetDimensions(dim.Width()/2, CallButtonHeight, LocalCoords);
  474.   speakerButton->SetPosition(dim.Width()/2, StatusWindowHeight);
  475.   makeCallButton = new PTextButton(this, PResourceString(IDS_MAKECALL), PCREATE_NOTIFIER(OnCallButton));
  476.   makeCallButton->SetDimensions(dim.Width(), CallButtonHeight, LocalCoords);
  477.   makeCallButton->SetPosition(0, StatusWindowHeight);
  478.   speakerEnable = new PCheckBox(this, PResourceString(IDS_SPEAKER), PCREATE_NOTIFIER(OnSpeakerEnable));
  479.   speakerEnable->SetValue(TRUE);
  480.   PDim boxSize = speakerEnable->GetDimensions(LocalCoords);
  481.   boxSize.AddWidth(4);
  482.   speakerEnable->SetDimensions(boxSize, LocalCoords);
  483.   PSCROLLBAR_VALUE spkrVolume = (PSCROLLBAR_VALUE)config.GetInteger(SpeakerVolumeConfigKey, 128);
  484.   speakerVolume = new PHorizontalScrollBar(this, PCREATE_NOTIFIER(OnSpeakerVolume),
  485.                                            255, 0, spkrVolume, 5, 25);
  486.   PDIMENSION scrollBarWidth = dim.Width()/2 - boxSize.Width();
  487.   speakerVolume->SetDimensions(scrollBarWidth, ScrollBarHeight, LocalCoords);
  488.   speakerVolume->SetPosition(0, StatusWindowHeight+CallButtonHeight);
  489.   speakerEnable->SetPosition(scrollBarWidth, StatusWindowHeight+CallButtonHeight+(ScrollBarHeight-boxSize.Height())/2);
  490.   microphoneEnable = new PCheckBox(this, PResourceString(IDS_MICROPHONE), PCREATE_NOTIFIER(OnMicrophoneEnable));
  491.   microphoneEnable->SetValue(TRUE);
  492.   boxSize = microphoneEnable->GetDimensions(LocalCoords);
  493.   boxSize.AddWidth(4);
  494.   microphoneEnable->SetDimensions(boxSize, LocalCoords);
  495.   microphoneEnable->SetPosition(dim.Width()/2-boxSize.Width(), StatusWindowHeight+CallButtonHeight+(ScrollBarHeight-boxSize.Height())/2);
  496.   PSCROLLBAR_VALUE mikeVolume = (PSCROLLBAR_VALUE)config.GetInteger(MicrophoneVolumeConfigKey, 128);
  497.   microphoneVolume = new PHorizontalScrollBar(this, PCREATE_NOTIFIER(OnMicrophoneVolume),
  498.                                               255, 0, mikeVolume, 5, 25);
  499.   microphoneVolume->SetDimensions(dim.Width()/2-boxSize.Width(), ScrollBarHeight, LocalCoords);
  500.   microphoneVolume->SetPosition(dim.Width()/2, StatusWindowHeight+CallButtonHeight);
  501.   AddSpeedDialButtons();
  502.   statisticsDialog = new StatisticsDlg(this);
  503.   statisticsDialog->Hide();
  504.   //display the window
  505.   UpdateCommandSources();
  506.   Show();
  507.   SetCallMode(IdleCallMode);
  508.   speakerphoneSwitch = FALSE;
  509.   // Get some parameters
  510.   autoAnswer = config.GetBoolean(AutoAnswerConfigKey, FALSE);
  511.   dtmfAsString = config.GetBoolean(DtmfAsStringConfigKey, TRUE);
  512.   maxRecentCalls = config.GetInteger(MaxRecentCallsConfigKey, 10);
  513.   noAnswerForwardParty = config.GetString(NoAnswerForwardPartyConfigKey);
  514.   noAnswerTime = PTimeInterval(0, config.GetInteger(NoAnswerTimeConfigKey, 30));
  515.   ringSoundFile = config.GetString(RingSoundFileConfigKey);
  516.   ringSoundTimer.SetNotifier(PCREATE_NOTIFIER(OnRingSoundAgain));
  517.   noAnswerTimer.SetNotifier(PCREATE_NOTIFIER(OnNoAnswerTimeout));
  518.   // Initialisation of H323 stuff
  519.   if (endpoint.Initialise(config)) {
  520.     OutputStatus(IDS_LISTENING);
  521.     endpoint.xJack.SetPlayVolume(OpalIxJDevice::POTSLine, spkrVolume);
  522.     endpoint.xJack.SetRecordVolume(OpalIxJDevice::POTSLine, mikeVolume);
  523.   }
  524.   else
  525.     SetCallMode(NoGatekeeperMode);
  526. }
  527. MainWindow::~MainWindow()
  528. {
  529.   currentCallMode = ApplicationShuttingDown;
  530.   // Do this now, if leave to endpoint destructor callbacks on the main window
  531.   // are accessing destroyed object.
  532.   endpoint.ClearAllCalls();
  533. #if PTRACING
  534.   if (myTraceFile) {
  535.     PTrace::SetStream(NULL);
  536.     myTraceFile->Close();
  537.   }
  538.   delete myTraceFile;
  539. #endif
  540. }
  541. void MainWindow::OutputStatus(PRESOURCE_ID strId, ...)
  542. {
  543.   if (currentCallMode == ApplicationShuttingDown)
  544.     return;
  545.   va_list args;
  546.   va_start(args, strId);
  547.   PResourceString fmt = strId;
  548.   PStringArray lines = pvsprintf(fmt, args).Lines();
  549.   for (PINDEX i = 0; i < lines.GetSize(); i++)
  550.     statusWindow->AddString(lines[i]);
  551.   PINDEX count = statusWindow->GetCount();
  552.   if (count > 3)
  553.     statusWindow->SetTopIndex(count - 3);
  554. }
  555. BOOL MainWindow::AllowClose(BOOL)
  556. {
  557.   PWaitAndSignal mutex(callModeMutex);
  558.   switch (currentCallMode) {
  559.     case IdleCallMode :
  560.     case NoGatekeeperMode :
  561.     case ApplicationShuttingDown :
  562.       break;
  563.     default :
  564.       if (!PSimpleDialog::YesNo(this, IDS_INCALLEXIT))
  565.         return FALSE;
  566.       break;
  567.   }
  568.   currentCallMode = ApplicationShuttingDown;
  569.   return TRUE;
  570. }
  571. void MainWindow::OnClose()
  572. {
  573.   PConfig config;
  574.   PPoint pos = GetPosition(PixelCoords);
  575.   config.SetInteger(MainWindowLeftConfigKey, pos.X());
  576.   config.SetInteger(MainWindowTopConfigKey, pos.Y());
  577.   PDim dim = GetDimensions(PixelCoords);
  578.   config.SetInteger(MainWindowWidthConfigKey, dim.Width());
  579.   config.SetInteger(MainWindowHeightConfigKey, dim.Height());
  580. }
  581. void MainWindow::OnResize(const PDim & newSize, ResizeType type)
  582. {
  583.   if (type != Normalised)
  584.     return;
  585.   statusWindow->SetDimensions(newSize.Width(), statusWindow->GetDimensions(PixelCoords).Height(), PixelCoords);
  586.   makeCallButton->SetDimensions(newSize.Width(), makeCallButton->GetDimensions(PixelCoords).Height(), PixelCoords);
  587.   answerButton->SetDimensions(newSize.Width()/2, answerButton->GetDimensions(PixelCoords).Height(), PixelCoords);
  588.   refuseButton->SetDimensions(newSize.Width()/2, refuseButton->GetDimensions(PixelCoords).Height(), PixelCoords);
  589.   refuseButton->SetPosition(newSize.Width()/2, refuseButton->GetPosition(PixelCoords).Y(), TopLeftPixels, TopLeftPixels);
  590.   hangUpButton->SetDimensions(newSize.Width()/2, hangUpButton->GetDimensions(PixelCoords).Height(), PixelCoords);
  591.   speakerButton->SetDimensions(newSize.Width()/2, speakerButton->GetDimensions(PixelCoords).Height(), PixelCoords);
  592.   speakerButton->SetPosition(newSize.Width()/2, speakerButton->GetPosition(PixelCoords).Y(), TopLeftPixels, TopLeftPixels);
  593.   PDIMENSION scrollBarWidth = newSize.Width()/2-speakerEnable->GetDimensions(PixelCoords).Width();
  594.   speakerVolume->SetDimensions(scrollBarWidth, speakerVolume->GetDimensions(PixelCoords).Height(), PixelCoords);
  595.   speakerEnable->SetPosition(scrollBarWidth, speakerEnable->GetPosition(PixelCoords).Y(), TopLeftPixels, TopLeftPixels);
  596.   scrollBarWidth = newSize.Width()/2-microphoneEnable->GetDimensions(PixelCoords).Width();
  597.   microphoneVolume->SetDimensions(scrollBarWidth, microphoneVolume->GetDimensions(PixelCoords).Height(), PixelCoords);
  598.   microphoneVolume->SetPosition(newSize.Width()/2, microphoneVolume->GetPosition(PixelCoords).Y(), TopLeftPixels, TopLeftPixels);
  599.   microphoneEnable->SetPosition(newSize.Width()/2+scrollBarWidth, microphoneEnable->GetPosition(PixelCoords).Y(), TopLeftPixels, TopLeftPixels);
  600.   if (speedDialButtons.IsEmpty())
  601.     return;
  602.   PDim dim = speedDialButtons[0].GetDimensions(PixelCoords);
  603.   PORDINATE top = speedDialButtons[0].GetPosition(PixelCoords).Y();
  604.   PORDINATE x = 0;
  605.   PORDINATE y = top;
  606.   for (PINDEX i = 0; i < speedDialButtons.GetSize(); i++) {
  607.     if ((PDIMENSION)y+dim.Height() > newSize.Height()) {
  608.       y = top;
  609.       x += dim.Width();
  610.       if ((PDIMENSION)x+dim.Width()/2 > newSize.Width())
  611.         break;
  612.     }
  613.     speedDialButtons[i].SetPosition(x, y, TopLeftPixels, TopLeftPixels);
  614.     y += dim.Height();
  615.   }
  616. }
  617. void MainWindow::SetCallMode(CallMode mode)
  618. {
  619.   PWaitAndSignal mutex(callModeMutex);
  620.   if (currentCallMode == ApplicationShuttingDown)
  621.     return;
  622.   currentCallMode = mode;
  623.   if (currentCallMode == ApplicationShuttingDown)
  624.     return;
  625.   makeCallButton->Show(mode == IdleCallMode ||
  626.                        mode == HangingUpMode ||
  627.                        mode == ActiveLineCallMode ||
  628.                        mode == NoGatekeeperMode);
  629.   makeCallButton->Enable(mode == IdleCallMode);
  630.   for (PINDEX i = 0; i < speedDialButtons.GetSize(); i++)
  631.     speedDialButtons[i].Show(mode == IdleCallMode);
  632.   answerButton->Show(mode == IncomingCallWait);
  633.   refuseButton->Show(mode == IncomingCallWait);
  634.   BOOL inCall = mode == MakingCallMode ||
  635.                 mode == Active323CallMode ||
  636.                 mode == ActiveLineCallMode;
  637.   hangUpButton->Show(inCall);
  638.   speakerButton->Show(inCall);
  639.   speakerButton->Enable(mode == Active323CallMode &&
  640.                         endpoint.xJack.IsLineOffHook(OpalIxJDevice::POTSLine));
  641.   myMainMenu->ind1->Enable(inCall);
  642.   myMainMenu->ind2->Enable(inCall);
  643.   myMainMenu->ind3->Enable(inCall);
  644.   myMainMenu->ind4->Enable(inCall);
  645.   myMainMenu->ind5->Enable(inCall);
  646.   myMainMenu->ind6->Enable(inCall);
  647.   myMainMenu->ind7->Enable(inCall);
  648.   myMainMenu->ind8->Enable(inCall);
  649.   myMainMenu->ind9->Enable(inCall);
  650.   myMainMenu->ind0->Enable(inCall);
  651.   myMainMenu->inds->Enable(inCall);
  652.   myMainMenu->indh->Enable(inCall);
  653.   if (!inCall)
  654.     statisticsDialog->Hide();
  655.   speakerEnable->Show(mode == Active323CallMode);
  656.   speakerVolume->Show(mode == Active323CallMode);
  657.   microphoneEnable->Show(mode == Active323CallMode);
  658.   microphoneVolume->Show(mode == Active323CallMode);
  659.   speakerVolume->Enable(endpoint.xJack.IsOpen());
  660.   microphoneVolume->Enable(endpoint.xJack.IsOpen());
  661. }
  662. void MainWindow::OnCallButton(PTextButton &, INT)
  663. {
  664.   CallCmd();
  665. }
  666. void MainWindow::CallCmd()
  667. {
  668.   if (!CanMakeCall())
  669.     return;
  670.   PConfig config(RecentCallsConfigSection);
  671.   MakeCallDialog dlg(this); // ask the user what address to call
  672.   dlg.recentCalls.SetSize(maxRecentCalls);
  673.   PINDEX i;
  674.   for (i = 0; i < maxRecentCalls; i++) {
  675.     dlg.recentCalls[i] = -1;
  676.     PString fullAddress = config.GetString(psprintf("%u", i+1));
  677.     if (!fullAddress) {
  678.       PINDEX at = fullAddress.Find('@');
  679.       if (at == P_MAX_INDEX)
  680.         dlg.addressBox->AddString(fullAddress);
  681.       else {
  682.         dlg.addressBox->AddString(fullAddress.Left(at));
  683.         dlg.recentCalls[i] = dlg.gatewayBox->AddString(fullAddress.Mid(at+1));
  684.       }
  685.     }
  686.   }
  687.   if (endpoint.xJack.IsLinePresent(OpalIxJDevice::PSTNLine))
  688.     dlg.gatewayBox->AddString(InternalGatewayName);
  689.   dlg.AddressChanged(*dlg.addressBox, PComboBox::EditChange);
  690.   if (!dlg.RunModal())
  691.     return;
  692.   for (i = 0; i < dlg.gatewayBox->GetCount(); i++) {
  693.     if (dlg.address == dlg.gatewayBox->GetString(i))
  694.       break;
  695.   }
  696.   if (i >= dlg.gatewayBox->GetCount()) {
  697.     PINDEX count = dlg.addressBox->GetCount();
  698.     if (count >= maxRecentCalls-1)
  699.       count = maxRecentCalls-1;
  700.     for (i = count; i > 0; i--)
  701.       config.SetString(psprintf("%u", i+1), config.GetString(psprintf("%u", i)));
  702.     if (dlg.gateway.IsEmpty())
  703.       config.SetString("1", dlg.address);
  704.     else
  705.       config.SetString("1", dlg.address + '@' + dlg.gateway);
  706.   }
  707.   MakeCall(dlg.address, dlg.gateway);
  708. }
  709. BOOL MainWindow::CanMakeCall()
  710. {
  711.   return currentCallMode == IdleCallMode;
  712. }
  713. void MakeCallDialog::AddressChanged(PComboBox & box, INT status)
  714. {
  715.   if (status != PComboBox::NewSelection)
  716.     ok->Enable(box.GetLength() > 0);
  717.   else {
  718.     PINDEX idx = box.GetCurrent();
  719.     if (idx >= recentCalls.GetSize() || recentCalls[idx] < 0)
  720.       gatewayBox->SetText("");
  721.     else {
  722.       gatewayBox->SetCurrent(recentCalls[idx]);
  723.       gateway = gatewayBox->GetString(recentCalls[idx]);
  724.     }
  725.     ok->Enable();
  726.   }
  727. }
  728. void MainWindow::HangupCmd()
  729. {
  730.   if (!CanHangupCall())
  731.     return;
  732.   endpoint.xJack.StopTone(OpalIxJDevice::POTSLine);
  733.   if (currentCallMode == ActiveLineCallMode) {
  734.     endpoint.xJack.SetLineOnHook(OpalIxJDevice::PSTNLine);
  735.     SetCallMode(IdleCallMode);
  736.   }
  737.   else {
  738.     endpoint.ClearCall(currentCallToken);
  739.     SetCallMode(HangingUpMode);
  740.   }
  741.   OutputStatus(IDS_HANGINGUP);
  742. }
  743. BOOL MainWindow::CanHangupCall()
  744. {
  745.   return currentCallMode == MakingCallMode ||
  746.          currentCallMode == Active323CallMode ||
  747.          currentCallMode == ActiveLineCallMode;
  748. }
  749. void MainWindow::OnHangUpButton(PTextButton &, INT)
  750. {
  751.   HangupCmd();
  752. }
  753. void MainWindow::OnSpeakerButton(PTextButton &, INT)
  754. {
  755.   speakerphoneSwitch = TRUE;
  756.   speakerButton->Disable();
  757.   OutputStatus(IDS_REPLACEHANDSET);
  758.   endpoint.xJack.DisableAudio(OpalIxJDevice::POTSLine);
  759. }
  760. void MainWindow::AcceptCallCmd()
  761. {
  762.   AnswerCall(TRUE);
  763. }
  764. BOOL MainWindow::CanAcceptCall()
  765. {
  766.   return currentCallMode == IncomingCallWait;
  767. }
  768. void MainWindow::OnAnswerButton(PTextButton &, INT)
  769. {
  770.   AcceptCallCmd();
  771. }
  772. void MainWindow::RefuseCallCmd()
  773. {
  774.   AnswerCall(FALSE);
  775. }
  776. BOOL MainWindow::CanRefuseCall()
  777. {
  778.   return currentCallMode == IncomingCallWait;
  779. }
  780. void MainWindow::OnRefuseButton(PTextButton &, INT)
  781. {
  782.   RefuseCallCmd();
  783. }
  784. void MainWindow::UserInputCmd(PMenuItem & item, INT)
  785. {
  786.   H323Connection * connection = endpoint.FindConnectionWithLock(currentCallToken);
  787.   if (connection == NULL)
  788.     return;
  789.   PString tone = item.GetString().Left(1);
  790.   OutputStatus(IDS_SENDINGTONE, (const char *)tone);
  791.   if (dtmfAsString)
  792.     connection->SendUserInput(tone);
  793.   else
  794.     connection->SendUserInputTone(tone[0]);
  795.   connection->Unlock();
  796. }
  797. void MainWindow::ShowStatsCmd()
  798. {
  799.   H323Connection * connection = endpoint.FindConnectionWithLock(currentCallToken);
  800.   if (connection == NULL)
  801.     return;
  802.   RTP_Session * session = connection->GetSession(RTP_Session::DefaultAudioSessionID);
  803.   if (session != NULL)
  804.     endpoint.OnRTPStatistics(*connection, *session);
  805.   connection->Unlock();
  806.   statisticsDialog->Show();
  807. }
  808. BOOL MainWindow::CanShowStats()
  809. {
  810.   return currentCallMode == Active323CallMode;
  811. }
  812. void MainWindow::OnMicrophoneEnable(PCheckBox &, INT)
  813. {
  814.   MuteMicrophoneCmd();
  815. }
  816. void MainWindow::MuteMicrophoneCmd()
  817. {
  818.   H323Connection * connection = endpoint.FindConnectionWithLock(currentCallToken);
  819.   if (connection == NULL)
  820.     return;
  821.   H323Channel * channel = connection->FindChannel(RTP_Session::DefaultAudioSessionID, FALSE);
  822.   if (channel != NULL) {
  823.     BOOL newState = !channel->IsPaused();
  824.     channel->SetPause(newState);
  825.     microphoneEnable->SetValue(!newState);
  826.   }
  827.   connection->Unlock();
  828. }
  829. BOOL MainWindow::CanMuteMicrophone()
  830. {
  831.   return currentCallMode == Active323CallMode;
  832. }
  833. void MainWindow::OnSpeakerEnable(PCheckBox &, INT)
  834. {
  835.   MuteSpeakerCmd();
  836. }
  837. void MainWindow::MuteSpeakerCmd()
  838. {
  839.   H323Connection * connection = endpoint.FindConnectionWithLock(currentCallToken);
  840.   if (connection == NULL)
  841.     return;
  842.   H323Channel * channel = connection->FindChannel(RTP_Session::DefaultAudioSessionID, TRUE);
  843.   if (channel != NULL) {
  844.     BOOL newState = !channel->IsPaused();
  845.     channel->SetPause(newState);
  846.     speakerEnable->SetValue(!newState);
  847.   }
  848.   connection->Unlock();
  849. }
  850. BOOL MainWindow::CanMuteSpeaker()
  851. {
  852.   return currentCallMode == Active323CallMode;
  853. }
  854. void MainWindow::OnSpeakerVolume(PHorizontalScrollBar & bar, INT status)
  855. {
  856.   endpoint.xJack.SetPlayVolume(OpalIxJDevice::POTSLine, bar.GetValue());
  857.   if (status == PScrollBar::EndTrack) {
  858.     PConfig config;
  859.     config.SetInteger(SpeakerVolumeConfigKey, bar.GetValue());
  860.   }
  861. }
  862. void MainWindow::OnMicrophoneVolume(PHorizontalScrollBar & bar, INT status)
  863. {
  864.   endpoint.xJack.SetRecordVolume(OpalIxJDevice::POTSLine, bar.GetValue());
  865.   if (status == PScrollBar::EndTrack) {
  866.     PConfig config;
  867.     config.SetInteger(MicrophoneVolumeConfigKey, bar.GetValue());
  868.   }
  869. }
  870. void MainWindow::ExitCmd()
  871. {
  872.   owner->Terminate();
  873. }
  874. void MainWindow::OnSpeedDialButton(PTextButton & button, INT)
  875. {
  876.   SpeedDial(button.GetName());
  877. }
  878. void MainWindow::AddSpeedDialButtons()
  879. {
  880.   PConfig config(SpeedDialConfigSection);
  881.   PINDEX i;
  882.   speedDialButtons.RemoveAll();
  883.   PStringList aliases = config.GetKeys();
  884.   for (i = 0; i < aliases.GetSize(); i++) {
  885.     PTextButton * button = new PTextButton(this, aliases[i]);
  886.     button->SetNotifier(PCREATE_NOTIFIER(OnSpeedDialButton));
  887.     speedDialButtons.Append(button);
  888.   }
  889.   PDIMENSION maxWidth = 0;
  890.   for (i = 0; i < speedDialButtons.GetSize(); i++) {
  891.     PDIMENSION width = speedDialButtons[i].GetDimensions(LocalCoords).Width();
  892.     if (maxWidth < width)
  893.       maxWidth = width;
  894.   }
  895.   for (i = 0; i < speedDialButtons.GetSize(); i++) {
  896.     speedDialButtons[i].SetDimensions(maxWidth, SpeedDialButtonHeight, LocalCoords);
  897.     speedDialButtons[i].SetPosition(0, StatusWindowHeight+CallButtonHeight);
  898.     speedDialButtons[i].Show();
  899.   }
  900.   OnResize(GetDimensions(PixelCoords), Normalised);
  901. }
  902. void MainWindow::SpeedDialOptionsCmd()
  903. {
  904.   SpeedDialOptionDlg dlg(this);
  905.   PConfig config(SpeedDialConfigSection);
  906.   PINDEX i;
  907.   PStringList aliases = config.GetKeys();
  908.   for (i = 0; i < aliases.GetSize(); i++)
  909.     dlg.speedDialList->AddString(aliases[i]+'t'+config.GetString(aliases[i]));
  910.   dlg.selectedSpeedDial = P_MAX_INDEX;
  911.   if (!dlg.RunModal())
  912.     return;
  913.   config.DeleteSection();
  914.   for (i = 0; i < dlg.speedDialList->GetCount(); i++) {
  915.     PString str = dlg.speedDialList->GetString(i);
  916.     PINDEX tab = str.Find('t');
  917.     config.SetString(str.Left(tab), str.Mid(tab+1));
  918.   }
  919.   AddSpeedDialButtons();
  920. }
  921. void SpeedDialOptionDlg::AddButton(PTextButton &, INT)
  922. {
  923.   speedDialList->AddString(alias+'t'+address+'t'+gateway);
  924.   alias = address = gateway;
  925.   UpdateControls();
  926.   EnableFields();
  927. }
  928. void SpeedDialOptionDlg::RemoveButton(PTextButton &, INT)
  929. {
  930.   PString str = speedDialList->GetString(selectedSpeedDial);
  931.   PINDEX tab1 = str.Find('t');
  932.   PINDEX tab2 = str.Find('t', tab1+1);
  933.   alias = str.Left(tab1);
  934.   address = str(tab1+1, tab2-1);
  935.   gateway = str.Mid(tab2+1);
  936.   speedDialList->DeleteEntry(selectedSpeedDial);
  937.   selectedSpeedDial = P_MAX_INDEX;
  938.   UpdateControls();
  939.   EnableFields();
  940. }
  941. void SpeedDialOptionDlg::UpButton(PTextButton &, INT)
  942. {
  943.   PINDEX selection = selectedSpeedDial;
  944.   speedDialList->InsertString(speedDialList->GetString(selection), selection-1, FALSE);
  945.   speedDialList->DeleteEntry(selection+1);
  946.   speedDialList->SetSelection(selection-1);
  947. }
  948. void SpeedDialOptionDlg::DownButton(PTextButton &, INT)
  949. {
  950.   PINDEX selection = selectedSpeedDial;
  951.   speedDialList->InsertString(speedDialList->GetString(selection), selection+2, FALSE);
  952.   speedDialList->DeleteEntry(selection);
  953.   speedDialList->SetSelection(selection+1);
  954. }
  955. void SpeedDialOptionDlg::SpeedDialSelect(PStringListBox &, INT)
  956. {
  957.   EnableFields();
  958. }
  959. void SpeedDialOptionDlg::AddressChanged(PEditBox &, INT)
  960. {
  961.   EnableFields();
  962. }
  963. void SpeedDialOptionDlg::EnableFields()
  964. {
  965.   addButton->Enable(!alias);
  966.   PINDEX count = speedDialList->GetCount();
  967.   removeButton->Enable(selectedSpeedDial < count);
  968.   upButton->Enable(selectedSpeedDial > 0 && selectedSpeedDial < count);
  969.   downButton->Enable(selectedSpeedDial < count-1);
  970. }
  971. void MainWindow::GeneralOptionsCmd()
  972. {
  973.   PConfig config;
  974.   GeneralOptionsDlg dlg(this);
  975.   dlg.username = endpoint.GetLocalUserName();
  976.   const PStringList & aliases = endpoint.GetAliasNames();
  977.   PINDEX i;
  978.   for (i = 1; i < aliases.GetSize(); i++)
  979.     dlg.aliasList->AddString(aliases[i]);
  980.   dlg.addAliasBtn->Disable();
  981.   dlg.delAliasBtn->Disable();
  982.   dlg.bandwidthType = config.GetInteger(BandwidthTypeConfigKey, 5);
  983.   dlg.bandwidth = endpoint.GetInitialBandwidth()/20.0;
  984.   dlg.bandwidthBox->Enable(dlg.bandwidthType == 6);
  985.   dlg.maxRecentCalls = maxRecentCalls;
  986.   dlg.ipTOS = endpoint.GetRtpIpTypeofService();
  987.   dlg.ringSoundFile = ringSoundFile;
  988.   dlg.playSoundButton->Enable(!ringSoundFile);
  989.   dlg.dtmfAsString = dtmfAsString;
  990.   dlg.autoAnswer = autoAnswer;
  991.   dlg.noFastStart = endpoint.noFastStart;
  992.   dlg.noTunneling = endpoint.noTunneling;
  993.   if (!dlg.RunModal())
  994.     return;
  995.   endpoint.SetLocalUserName(dlg.username);
  996.   config.SetString(UsernameConfigKey, dlg.username);
  997.   for (i = 0; i < dlg.aliasList->GetCount(); i++) {
  998.     PString alias = dlg.aliasList->GetString(i);
  999.     endpoint.AddAliasName(alias);
  1000.     config.SetString(psprintf(AliasConfigKey, i), alias);
  1001.   }
  1002.   config.DeleteKey(psprintf(AliasConfigKey, i));
  1003.   autoAnswer = dlg.autoAnswer;
  1004.   config.SetBoolean(AutoAnswerConfigKey, autoAnswer);
  1005.   dtmfAsString = dlg.dtmfAsString;
  1006.   config.SetBoolean(DtmfAsStringConfigKey, dtmfAsString);
  1007.   endpoint.noFastStart = dlg.noFastStart;
  1008.   config.SetBoolean(NoFastStartConfigKey, dlg.noFastStart);
  1009.   endpoint.noTunneling = dlg.noTunneling;
  1010.   config.SetBoolean(NoTunnelingConfigKey, dlg.noTunneling);
  1011.   endpoint.SetInitialBandwidth((unsigned)(dlg.bandwidth*20));
  1012.   config.SetReal(BandwidthConfigKey, dlg.bandwidth);
  1013.   config.SetInteger(BandwidthTypeConfigKey, dlg.bandwidthType);
  1014.   maxRecentCalls = dlg.maxRecentCalls;
  1015.   config.SetInteger(MaxRecentCallsConfigKey, maxRecentCalls);
  1016.   endpoint.SetRtpIpTypeofService(dlg.ipTOS);
  1017.   config.SetInteger(IpTosConfigKey, dlg.ipTOS);
  1018.   ringSoundFile = dlg.ringSoundFile;
  1019.   config.SetString(RingSoundFileConfigKey, ringSoundFile);
  1020. }
  1021. void GeneralOptionsDlg::ChangedUsername(PEditBox & box, INT)
  1022. {
  1023.   ok->Enable(box.GetLength() > 0);
  1024. }
  1025. void GeneralOptionsDlg::ChangedAlias(PEditBox & box, INT)
  1026. {
  1027.   addAliasBtn->Enable(box.GetLength() > 0);
  1028. }
  1029. void GeneralOptionsDlg::AddAlias(PTextButton &, INT)
  1030. {
  1031.   aliasList->AddString(alias);
  1032.   alias = PString();
  1033.   UpdateControls();
  1034. }
  1035. void GeneralOptionsDlg::DelAlias(PTextButton &, INT)
  1036. {
  1037.   alias = aliasList->GetSelectedString();
  1038.   aliasList->DeleteString(aliasList->GetSelection());
  1039.   UpdateControls();
  1040. }
  1041. void GeneralOptionsDlg::SelectAlias(PStringListBox & box, INT)
  1042. {
  1043.   delAliasBtn->Enable(box.GetSelection() != P_MAX_INDEX);
  1044. }
  1045. void GeneralOptionsDlg::BandwidthChange(PChoiceBox &, INT)
  1046. {
  1047.   bandwidthBox->Enable(bandwidthType == 6);
  1048.   if (bandwidthType < 6) {
  1049.     static int const bandwidths[6] = {
  1050.       14400, 28800, 64000, 128000, 1500000, 10000000
  1051.     };
  1052.     bandwidth = bandwidths[bandwidthType]/1000.0;
  1053.     UpdateControls();
  1054.   }
  1055. }
  1056. void GeneralOptionsDlg::ChangedSoundFile(PEditBox & box, INT)
  1057. {
  1058.   playSoundButton->Enable(box.GetLength() > 0);
  1059. }
  1060. void GeneralOptionsDlg::BrowseSound(PTextButton &, INT)
  1061. {
  1062.   POpenFileDialog dlg(this);
  1063.   dlg.AddFileType(".wav");
  1064.   if (dlg.RunModal()) {
  1065.     ringSoundFile = dlg.GetFile();
  1066.     UpdateControls();
  1067.   }
  1068. }
  1069. void GeneralOptionsDlg::PlaySoundFile(PTextButton &, INT)
  1070. {
  1071.   PSound::PlayFile(ringSoundFile, FALSE);
  1072. }
  1073. void MainWindow::ForwardingOptionsCmd()
  1074. {
  1075.   PConfig config;
  1076.   ForwardingOptionsDlg dlg(this);
  1077.   dlg.alwaysForwardParty = endpoint.alwaysForwardParty;
  1078.   dlg.busyForwardParty = endpoint.busyForwardParty;
  1079.   dlg.noAnswerForwardParty = noAnswerForwardParty;
  1080.   dlg.noAnswerTime = noAnswerTime.GetSeconds();
  1081.   if (!dlg.RunModal())
  1082.     return;
  1083.   endpoint.alwaysForwardParty = dlg.alwaysForwardParty;
  1084.   config.SetString(AlwaysForwardPartyConfigKey, endpoint.alwaysForwardParty);
  1085.   endpoint.busyForwardParty = dlg.busyForwardParty;
  1086.   config.SetString(BusyForwardPartyConfigKey, endpoint.busyForwardParty);
  1087.   noAnswerForwardParty = dlg.noAnswerForwardParty;
  1088.   config.SetString(NoAnswerForwardPartyConfigKey, noAnswerForwardParty);
  1089.   noAnswerTime = PTimeInterval(0, dlg.noAnswerTime);
  1090.   config.SetInteger(NoAnswerTimeConfigKey, dlg.noAnswerTime);
  1091. }
  1092. void MainWindow::GatekeeperOptionsCmd()
  1093. {
  1094.   GatekeeperOptionsDlg dlg(this);
  1095.   PConfig config;
  1096.   dlg.useGatekeeper = config.GetBoolean(UseGatekeeperConfigKey, FALSE);
  1097.   dlg.gatekeeperHost = config.GetString(GatekeeperHostConfigKey);
  1098.   dlg.discover = dlg.gatekeeperHost.IsEmpty() ? 1 : 2;
  1099.   dlg.requireGatekeeper = config.GetBoolean(RequireGatekeeperConfigKey, FALSE);
  1100.   dlg.EnableFields();
  1101.   if (!dlg.RunModal())
  1102.     return;
  1103.   config.SetBoolean(UseGatekeeperConfigKey, dlg.useGatekeeper);
  1104.   if (dlg.discover == 1)
  1105.     config.SetString(GatekeeperHostConfigKey, "");
  1106.   else
  1107.     config.SetString(GatekeeperHostConfigKey, dlg.gatekeeperHost);
  1108.   config.SetBoolean(RequireGatekeeperConfigKey, dlg.requireGatekeeper);
  1109.   if (endpoint.FindGatekeeper(config))
  1110.     SetCallMode(IdleCallMode);
  1111.   else
  1112.     SetCallMode(NoGatekeeperMode);
  1113. }
  1114. BOOL MainWindow::CanSetGatekeeper()
  1115. {
  1116.   return currentCallMode == IdleCallMode ||
  1117.          currentCallMode == NoGatekeeperMode;
  1118. }
  1119. void GatekeeperOptionsDlg::UsingGatekeeper(PCheckBox &, INT)
  1120. {
  1121.   EnableFields();
  1122. }
  1123. void GatekeeperOptionsDlg::CheckDiscover(PRadioButton &, INT)
  1124. {
  1125.   EnableFields();
  1126. }
  1127. void GatekeeperOptionsDlg::EnableFields()
  1128. {
  1129.   discoverButton->Enable(useGatekeeper);
  1130.   staticGkButton->Enable(useGatekeeper);
  1131.   gatekeeperHostBox->Enable(useGatekeeper && discover == 2);
  1132.   requireBox->Enable(useGatekeeper);
  1133. }
  1134. void MainWindow::AudioOptionsCmd()
  1135. {
  1136.   PConfig config;
  1137.   AudioOptionsDlg dlg(this);
  1138.   dlg.cardSelection = endpoint.xJack.IsOpen() ? 2 : 1;
  1139.   PINDEX i;
  1140.   PStringArray playDevices = PSoundChannel::GetDeviceNames(PSoundChannel::Player);
  1141.   for (i = 0; i < playDevices.GetSize(); i++)
  1142.     dlg.playDeviceBox->AddString(playDevices[i]);
  1143.   dlg.playSoundDevice = dlg.playDeviceBox->FindString(endpoint.GetSoundChannelPlayDevice());
  1144.   PStringArray recordDevices = PSoundChannel::GetDeviceNames(PSoundChannel::Recorder);
  1145.   for (i = 0; i < recordDevices.GetSize(); i++)
  1146.     dlg.recordDeviceBox->AddString(recordDevices[i]);
  1147.   dlg.recordSoundDevice = dlg.recordDeviceBox->FindString(endpoint.GetSoundChannelRecordDevice());
  1148.   dlg.soundBuffers = endpoint.GetSoundChannelBufferDepth();
  1149.   PStringArray xJackDevices = OpalIxJDevice::GetDeviceNames();
  1150.   dlg.quickNetButton->Enable(!xJackDevices.IsEmpty());
  1151.   for (i = 0; i < xJackDevices.GetSize(); i++)
  1152.     dlg.xJackDeviceBox->AddString(xJackDevices[i]);
  1153.   PINDEX previousDevice;
  1154.   PStringArray devices = OpalIxJDevice::GetDeviceNames();
  1155.   if (devices.GetSize() == 0)
  1156.     previousDevice = 0;
  1157.   else {
  1158.     previousDevice = dlg.xJackDeviceBox->FindString(config.GetString(QuicknetDeviceConfigKey, devices[0]));
  1159.     if (previousDevice == P_MAX_INDEX)
  1160.       previousDevice = 0;
  1161.   }
  1162.   dlg.xJackDevice = previousDevice;
  1163.   dlg.aecLevel = config.GetInteger(AECConfigKey, 2);
  1164.   dlg.silenceDetect = endpoint.silenceDetect;
  1165.   i = 0;
  1166.   for (;;) {
  1167.     PString key = psprintf(CodecsConfigKey, ++i);
  1168.     PString name = config.GetString(CodecsConfigSection, key, "");
  1169.     if (name.IsEmpty())
  1170.       break;
  1171.     dlg.codecList->AddString(name);
  1172.   }
  1173.   dlg.SelectCodec(*dlg.codecList, 0);
  1174.   dlg.enabledCodec->Disable();
  1175.   dlg.packetSizeBox->Disable();
  1176.   dlg.jitter = endpoint.GetMaxAudioDelayJitter();
  1177.   dlg.SelectCard(*(PRadioButton *)NULL, 0);
  1178.   if (!dlg.RunModal())
  1179.     return;
  1180.   config.SetBoolean(UseQuicknetConfigKey, dlg.cardSelection == 2);
  1181.   if (dlg.cardSelection == 1 && endpoint.xJack.IsOpen())
  1182.     endpoint.CloseQuicknet();
  1183.   PString str = dlg.playDeviceBox->GetString(dlg.playSoundDevice);
  1184.   config.SetString(SoundPlayConfigKey, str);
  1185.   endpoint.SetSoundChannelPlayDevice(str);
  1186.   str = dlg.recordDeviceBox->GetString(dlg.recordSoundDevice);
  1187.   config.SetString(SoundRecordConfigKey, str);
  1188.   endpoint.SetSoundChannelRecordDevice(str);
  1189.   config.SetInteger(SoundBuffersConfigKey, dlg.soundBuffers);
  1190.   endpoint.SetSoundChannelBufferDepth(dlg.soundBuffers);
  1191.   str = dlg.xJackDeviceBox->GetString(dlg.xJackDevice);
  1192.   config.SetString(QuicknetDeviceConfigKey, str);
  1193.   config.SetInteger(SoundBuffersConfigKey, dlg.soundBuffers);
  1194.   config.SetInteger(AECConfigKey, dlg.aecLevel);
  1195.   endpoint.xJack.SetAEC(OpalIxJDevice::POTSLine, (OpalIxJDevice::AECLevels)dlg.aecLevel);
  1196.   endpoint.silenceDetect = dlg.silenceDetect;
  1197.   config.SetBoolean(SilenceDetectConfigKey, dlg.silenceDetect);
  1198.   if (GetCallMode() == Active323CallMode) {
  1199.     H323Connection * connection = endpoint.FindConnectionWithLock(currentCallToken);
  1200.     if (connection != NULL) {
  1201.       H323Channel * channel = connection->FindChannel(RTP_Session::DefaultAudioSessionID, FALSE);
  1202.       if (channel != NULL) {
  1203.         H323Codec * codec = channel->GetCodec();
  1204.         if (codec != NULL && codec->IsDescendant(H323AudioCodec::Class())) {
  1205.           H323AudioCodec::SilenceDetectionMode newMode = 
  1206.                               dlg.silenceDetect ? H323AudioCodec::AdaptiveSilenceDetection
  1207.                                                 : H323AudioCodec::NoSilenceDetection;
  1208.           if (((H323AudioCodec*)codec)->GetSilenceDetectionMode() != newMode)
  1209.             ((H323AudioCodec*)codec)->SetSilenceDetectionMode(newMode);
  1210.         }
  1211.       }
  1212.       connection->Unlock();
  1213.     }
  1214.   }
  1215.   if (dlg.cardSelection == 2 && (!endpoint.xJack.IsOpen() || dlg.xJackDevice != previousDevice))
  1216.     endpoint.OpenQuicknet(config);
  1217.   endpoint.SetMaxAudioDelayJitter(dlg.jitter);
  1218.   config.SetInteger(JitterConfigKey, dlg.jitter);
  1219.   PString oldSection = config.GetDefaultSection();
  1220.   config.SetDefaultSection(CodecsConfigSection);
  1221.   config.DeleteSection();
  1222.   for (i = 0; i < dlg.codecList->GetCount(); i++)
  1223.     config.SetString(psprintf(CodecsConfigKey, i+1), dlg.codecList->GetString(i));
  1224.   config.SetDefaultSection(oldSection);
  1225.   endpoint.LoadCapabilities(config);
  1226. }
  1227. void AudioOptionsDlg::SelectCard(PRadioButton &, INT)
  1228. {
  1229.   playDeviceTitle->Enable(cardSelection == 1);
  1230.   playDeviceBox->Enable(cardSelection == 1);
  1231.   recordDeviceTitle->Enable(cardSelection == 1);
  1232.   recordDeviceBox->Enable(cardSelection == 1);
  1233.   soundBuffersTitle->Enable(cardSelection == 1);
  1234.   soundBuffersBox->Enable(cardSelection == 1);
  1235.   xJackDeviceTitle->Enable(cardSelection == 2);
  1236.   xJackDeviceBox->Enable(cardSelection == 2);
  1237.   aecTitle->Enable(cardSelection == 2);
  1238.   aecBox->Enable(cardSelection == 2);
  1239. }
  1240. void AudioOptionsDlg::SelectCodec(PStringListBox & list, INT)
  1241. {
  1242.   PINDEX selection = list.GetSelection();
  1243.   PINDEX count = list.GetCount();
  1244.   up->Enable(selection > 0 && selection < count);
  1245.   down->Enable(selection < count-1);
  1246.   enabledCodec->Enable(selection < count);
  1247.   packetSizeBox->Enable(selection < count);
  1248.   PString value = list.GetString(selection);
  1249.   enabledCodec->SetValue(value.Find(OffCodecSuffix) == P_MAX_INDEX);
  1250.   PINDEX left = value.FindLast('[');
  1251.   PINDEX right = value.FindLast(']');
  1252.   if (left != P_MAX_INDEX && right != P_MAX_INDEX)
  1253.     packetSizeBox->SetValue(value(left+1, right-1).AsUnsigned());
  1254. }
  1255. void AudioOptionsDlg::MoveUp(PTextButton &, INT)
  1256. {
  1257.   PINDEX selection = codecList->GetSelection();
  1258.   codecList->InsertString(codecList->GetString(selection), selection-1, FALSE);
  1259.   codecList->DeleteEntry(selection+1);
  1260.   codecList->SetSelection(selection-1);
  1261. }
  1262. void AudioOptionsDlg::MoveDown(PTextButton &, INT)
  1263. {
  1264.   PINDEX selection = codecList->GetSelection();
  1265.   codecList->InsertString(codecList->GetString(selection), selection+2, FALSE);
  1266.   codecList->DeleteEntry(selection);
  1267.   codecList->SetSelection(selection+1);
  1268. }
  1269. void AudioOptionsDlg::EnableCodec(PCheckBox & box, INT)
  1270. {
  1271.   PINDEX selection = codecList->GetSelection();
  1272.   if (selection == P_MAX_INDEX)
  1273.     return;
  1274.   PString str = codecList->GetString(selection);
  1275.   if (box.GetValue())
  1276.     str.Replace(OffCodecSuffix, OnCodecSuffix);
  1277.   else
  1278.     str.Replace(OnCodecSuffix, OffCodecSuffix);
  1279.   codecList->SetString(str, selection);
  1280.   codecList->SetSelection(selection);
  1281. }
  1282. void AudioOptionsDlg::PacketSizeChange(PIntegerEditBox & box, INT code)
  1283. {
  1284.   if (code != PEditBox::EndEdit)
  1285.     return;
  1286.   PINDEX selection = codecList->GetSelection();
  1287.   if (selection == P_MAX_INDEX)
  1288.     return;
  1289.   PString str = codecList->GetString(selection);
  1290.   PINDEX left = str.FindLast('[');
  1291.   PINDEX right = str.FindLast(']');
  1292.   if (left != P_MAX_INDEX && right != P_MAX_INDEX) {
  1293.     str.Splice(psprintf("%u", box.GetValue()), left+1, right-left-1);
  1294.     codecList->SetString(str, selection);
  1295.     codecList->SetSelection(selection);
  1296.   }
  1297. }
  1298. void MainWindow::VideoOptionsCmd()
  1299. {
  1300.   PConfig config;
  1301.   VideoOptionsDlg dlg(this);
  1302.   dlg.rxqcif = config.GetBoolean(H261QCIFConfigKey, TRUE);
  1303.   dlg.rxcif = config.GetBoolean(H261CIFConfigKey, TRUE);
  1304.   dlg.rxauto = config.GetBoolean(AutoReceiveVideoConfigKey, TRUE);
  1305.   dlg.txsize = config.GetInteger(VideoSizeConfigKey, 1);
  1306.   dlg.source = config.GetInteger(VideoSourceConfigKey, 1);
  1307.   dlg.format = config.GetInteger(VideoFormatConfigKey, 1);
  1308.   dlg.quality = config.GetInteger(VideoQualityConfigKey, 15);
  1309.   if (!dlg.RunModal())
  1310.     return;
  1311.   config.SetBoolean(H261QCIFConfigKey, dlg.rxqcif);
  1312.   config.SetBoolean(H261CIFConfigKey, dlg.rxcif);
  1313.   config.SetBoolean(AutoReceiveVideoConfigKey, dlg.rxauto);
  1314.   config.SetInteger(VideoSizeConfigKey, dlg.txsize);
  1315.   config.SetInteger(VideoSourceConfigKey, dlg.source);
  1316.   config.SetInteger(VideoFormatConfigKey, dlg.format);
  1317.   config.SetInteger(VideoQualityConfigKey, dlg.quality);
  1318.   endpoint.LoadCapabilities(config);
  1319. }
  1320. #if PTRACING
  1321. void MainWindow::TraceOptionsCmd()
  1322. {
  1323.   TraceOptionsDlg dlg(this);
  1324.   PConfig config;
  1325.   dlg.traceFlag = myTraceFile != NULL; // tracing has been enabled
  1326.   if (myTraceFile != NULL)
  1327.     dlg.traceFile = myTraceFile->GetName();
  1328.   else
  1329.     dlg.traceFile = PFilePath("trace.txt");
  1330.   dlg.traceLevel = PTrace::GetLevel();
  1331.   dlg.traceBlocks = (PTrace::GetOptions()&PTrace::Blocks) != 0;
  1332.   dlg.dateAndTime = (PTrace::GetOptions()&PTrace::DateAndTime) != 0;
  1333.   dlg.timestamp = (PTrace::GetOptions()&PTrace::Timestamp) != 0;
  1334.   dlg.threads = (PTrace::GetOptions()&PTrace::Thread) != 0;
  1335.   dlg.threadAddr = (PTrace::GetOptions()&PTrace::ThreadAddress) != 0;
  1336.   dlg.levelDisplay = (PTrace::GetOptions()&PTrace::TraceLevel) != 0;
  1337.   dlg.fileAndLine = (PTrace::GetOptions()&PTrace::FileAndLine) != 0;
  1338.   dlg.TraceSet(*(PCheckBox *)NULL, 0);
  1339.   if (!dlg.RunModal())
  1340.     return;
  1341.   if (dlg.traceFlag)
  1342.     config.SetString(TraceFileConfigKey, dlg.traceFile);
  1343.   else
  1344.     config.SetString(TraceFileConfigKey, "");
  1345.   config.SetInteger(TraceLevelConfigKey, dlg.traceLevel);
  1346.   config.SetBoolean(TraceBlockConfigKey, dlg.traceBlocks);
  1347.   config.SetBoolean(TraceDateTimeConfigKey, dlg.dateAndTime);
  1348.   config.SetBoolean(TraceTimestampConfigKey, dlg.timestamp);
  1349.   config.SetBoolean(TraceThreadsConfigKey, dlg.threads);
  1350.   config.SetBoolean(TraceThreadAddresssConfigKey, dlg.threadAddr);
  1351.   config.SetBoolean(TraceLevelDisplayConfigKey, dlg.levelDisplay);
  1352.   config.SetBoolean(TraceFileLineConfigKey, dlg.fileAndLine);
  1353.   OpenTraceFile(config);
  1354. }
  1355. void TraceOptionsDlg::TraceSet(PCheckBox &, INT)
  1356. {
  1357.   traceLevelText->Enable(traceFlag);
  1358.   traceLevelBox->Enable(traceFlag);
  1359.   traceOutText->Enable(traceFlag);
  1360.   traceOutBox->Enable(traceFlag);
  1361.   traceBlocksBox->Enable(traceFlag);
  1362.   dateAndTimeBox->Enable(traceFlag);
  1363.   timestampBox->Enable(traceFlag);
  1364.   threadsBox->Enable(traceFlag);
  1365.   threadAddrBox->Enable(traceFlag);
  1366.   levelDisplayBox->Enable(traceFlag);
  1367.   fileAndLineBox->Enable(traceFlag);
  1368. }
  1369. static void SetTraceOption(PConfig & config, const char * key, unsigned option)
  1370. {
  1371.   if (config.GetBoolean(key))
  1372.     PTrace::SetOptions(option);
  1373.   else
  1374.     PTrace::ClearOptions(option);
  1375. }
  1376. BOOL MainWindow::OpenTraceFile(PConfig & config)
  1377. {
  1378.   PTrace::SetLevel(config.GetInteger(TraceLevelConfigKey, 1));
  1379.   SetTraceOption(config, TraceBlockConfigKey, PTrace::Blocks);
  1380.   SetTraceOption(config, TraceDateTimeConfigKey, PTrace::DateAndTime);
  1381.   SetTraceOption(config, TraceTimestampConfigKey, PTrace::Timestamp);
  1382.   SetTraceOption(config, TraceThreadsConfigKey, PTrace::Thread);
  1383.   SetTraceOption(config, TraceThreadAddresssConfigKey, PTrace::ThreadAddress);
  1384.   SetTraceOption(config, TraceLevelDisplayConfigKey, PTrace::TraceLevel);
  1385.   SetTraceOption(config, TraceFileLineConfigKey, PTrace::FileAndLine);
  1386.   PString traceFileName = config.GetString(TraceFileConfigKey);
  1387.   // If already have a trace file, see if need to close it
  1388.   if (myTraceFile != NULL) {
  1389.     // If no change, do nothing more
  1390.     if (myTraceFile->GetFilePath() == PFilePath(traceFileName))
  1391.       return TRUE;
  1392.     PTrace::SetStream(NULL);
  1393.     delete myTraceFile;
  1394.     myTraceFile = NULL;
  1395.   }
  1396.   // Have stopped
  1397.   if (traceFileName.IsEmpty())
  1398.     return TRUE;
  1399.   PTextFile * traceFile = new PTextFile;
  1400.   if (traceFile->Open(traceFileName, PFile::WriteOnly)) {
  1401.     myTraceFile = traceFile;
  1402.     PTrace::SetStream(traceFile);
  1403.     PProcess & process = PProcess::Current();
  1404.     PTRACE(0, process.GetName()
  1405.            << " Version " << process.GetVersion(TRUE)
  1406.            << " by " << process.GetManufacturer()
  1407.            << " on " << process.GetOSClass() << ' ' << process.GetOSName()
  1408.            << " (" << process.GetOSVersion() << '-' << process.GetOSHardware() << ')');
  1409.     return TRUE;
  1410.   }
  1411.   PSimpleDialog::Error(this, IDS_TRACE_FAIL, (const char *)traceFile->GetName());
  1412.   delete traceFile;
  1413.   return FALSE;
  1414. }
  1415. #endif
  1416. void StatisticsDlg::OnCancel()
  1417. {
  1418.   Hide();
  1419. }
  1420. BOOL MainWindow::SpeedDial(const PString & key)
  1421. {
  1422.   PConfig config(SpeedDialConfigSection);
  1423.   PString str = config.GetString(key);
  1424.   if (str.IsEmpty())
  1425.     return FALSE;
  1426.   PINDEX tab = str.Find('t');
  1427.   if (tab != P_MAX_INDEX)
  1428.     return MakeCall(str.Left(tab), str.Mid(tab+1));
  1429.   else
  1430.     return MakeCall(str, "");
  1431. }
  1432. BOOL MainWindow::MakeCall(const PString & address, const PString & gateway)
  1433. {
  1434.   PString fullAddress = address;
  1435.   if (!gateway)
  1436.     fullAddress += '@' + gateway;
  1437.   OutputStatus(IDS_CALLING, (const char *)fullAddress);
  1438.   if (gateway *= InternalGatewayName) {
  1439.     if (!endpoint.xJack.IsLinePresent(OpalIxJDevice::PSTNLine))
  1440.       return FALSE;
  1441.     SetCallMode(ActiveLineCallMode);
  1442.     endpoint.xJack.SetLineToLineDirect(OpalIxJDevice::POTSLine, OpalIxJDevice::PSTNLine, TRUE);
  1443.     switch (endpoint.xJack.DialOut(OpalIxJDevice::PSTNLine, address)) {
  1444.       case OpalLineInterfaceDevice::DialTone :
  1445.         OutputStatus(IDS_NODIALTONE);
  1446.         break;
  1447.       case OpalLineInterfaceDevice::BusyTone :
  1448.         OutputStatus(IDS_LINEBUSY, (const char *)address);
  1449.         break;
  1450.       case OpalLineInterfaceDevice::RingTone :
  1451.         OutputStatus(IDS_LINECALLDIALLED);
  1452.         break;
  1453.       default :
  1454.         OutputStatus(IDS_LINECALLFAILED);
  1455.         break;
  1456.     }
  1457.     return TRUE;
  1458.   }
  1459.   SetCallMode(MakingCallMode);
  1460.   endpoint.xJack.PlayTone(OpalIxJDevice::POTSLine, OpalLineInterfaceDevice::RingTone);
  1461.   if (endpoint.MakeCall(fullAddress, currentCallToken))
  1462.     return TRUE;
  1463.   OutputStatus(IDS_INVALIDADDRESS, (const char *)fullAddress);
  1464.   SetCallMode(IdleCallMode);
  1465.   return FALSE;
  1466. }
  1467. void MainWindow::AnswerCall(BOOL accept)
  1468. {
  1469.   if (currentCallMode != IncomingCallWait)
  1470.     return;
  1471.   endpoint.xJack.RingLine(OpalIxJDevice::POTSLine, 0);
  1472.   ringSoundTimer.Stop();
  1473.   noAnswerTimer.Stop();
  1474.   H323Connection * connection = endpoint.FindConnectionWithLock(currentCallToken);
  1475.   if (connection == NULL)
  1476.     SetCallMode(IdleCallMode);
  1477.   else {
  1478.     connection->AnsweringCall(accept ? H323Connection::AnswerCallNow
  1479.                                      : H323Connection::AnswerCallDenied);
  1480.     connection->Unlock();
  1481.   }
  1482. }
  1483. BOOL MainWindow::OnAnswerCall(const PString & token, const PString & caller)
  1484. {
  1485.   currentCallToken = token;
  1486.   PTime now;
  1487.   PString nowStr = now.AsString("w h:m a");
  1488.   OutputStatus(IDS_INCOMINGCALL, (const char *)caller, (const char *)nowStr);
  1489.   // Check for auto answer option
  1490.   if (autoAnswer) {
  1491.     SetCallMode(Active323CallMode);
  1492.     return TRUE;
  1493.   }
  1494.   SetCallMode(IncomingCallWait);
  1495.   if (endpoint.xJack.IsOpen())
  1496.     endpoint.xJack.RingLine(OpalIxJDevice::POTSLine, RingCadence);
  1497.   if (!ringSoundFile) {
  1498.     PSound::PlayFile(ringSoundFile, FALSE);
  1499.     ringSoundTimer.RunContinuous(5000);
  1500.   }
  1501.   if (!noAnswerForwardParty)
  1502.     noAnswerTimer = noAnswerTime;
  1503.   return FALSE;
  1504. }
  1505. void MainWindow::OnNoAnswerTimeout(PTimer &, INT)
  1506. {
  1507.   H323Connection * connection = endpoint.FindConnectionWithLock(currentCallToken);
  1508.   if (connection != NULL) {
  1509.     connection->ForwardCall(noAnswerForwardParty);
  1510.     connection->Unlock();
  1511.   }
  1512. }
  1513. void MainWindow::OnRingSoundAgain(PTimer &, INT)
  1514. {
  1515.   if (!ringSoundFile)
  1516.     PSound::PlayFile(ringSoundFile, FALSE);
  1517. }
  1518. BOOL MainWindow::OnConnectionForwarded(const PString & forwardParty)
  1519. {
  1520.   PTime now;
  1521.   PString nowStr = now.AsString("w h:m a");
  1522.   OutputStatus(IDS_FORWARDING, (const char *)forwardParty, (const char *)nowStr);
  1523.   SetCallMode(MakingCallMode);
  1524.   if (MakeCall(forwardParty, ""))
  1525.     return TRUE;
  1526.   OutputStatus(IDS_INVALIDADDRESS, (const char *)forwardParty);
  1527.   SetCallMode(IdleCallMode);
  1528.   return FALSE;
  1529. }
  1530. void MainWindow::OnConnectionEstablished(const PString & token, const PString & party)
  1531. {
  1532.   currentCallToken = token;
  1533.   OutputStatus(IDS_TALKING, (const char *)party);
  1534.   SetCallMode(Active323CallMode);
  1535. }
  1536. void MainWindow::OnConnectionCleared(const H323Connection & connection)
  1537. {
  1538.   ringSoundTimer.Stop();
  1539.   noAnswerTimer.Stop();
  1540.   PString remoteParty = connection.GetRemotePartyName();
  1541.   if (remoteParty.IsEmpty()) {
  1542.     remoteParty = connection.GetControlChannel().GetRemoteAddress();
  1543.     if (strncmp(remoteParty, "ip$", 3) == 0) {
  1544.       remoteParty.Delete(0, 3);
  1545.       remoteParty.Delete(remoteParty.Find(':'), P_MAX_INDEX);
  1546.     }
  1547.   }
  1548.   PStringStream duration;
  1549.   duration << setprecision(0) << setw(5)
  1550.            << (PTime() - connection.GetConnectionStartTime());
  1551.   const char * remoteNameString = remoteParty;
  1552.   const char * durationString = duration;
  1553.   switch (connection.GetCallEndReason()) {
  1554.     case H323Connection::EndedByRemoteUser :
  1555.       OutputStatus(IDS_REMOTEHUNGUP, remoteNameString, durationString);
  1556.       break;
  1557.     case H323Connection::EndedByCallerAbort :
  1558.       OutputStatus(IDS_REMOTESTOPPED, remoteNameString);
  1559.       break;
  1560.     case H323Connection::EndedByRefusal :
  1561.       OutputStatus(IDS_REFUSED, remoteNameString);
  1562.       break;
  1563.     case H323Connection::EndedByNoAnswer :
  1564.       OutputStatus(IDS_NOANSWER, remoteNameString);
  1565.       break;
  1566.     case H323Connection::EndedByTransportFail :
  1567.       OutputStatus(IDS_ABNORMAL, remoteNameString, durationString);
  1568.       break;
  1569.     case H323Connection::EndedByNoUser :
  1570.       OutputStatus(IDS_NOUSER, remoteNameString);
  1571.       break;
  1572.     case H323Connection::EndedByNoBandwidth :
  1573.       OutputStatus(IDS_NOBANDWIDTH, remoteNameString);
  1574.       break;
  1575.     case H323Connection::EndedByCapabilityExchange :
  1576.       OutputStatus(IDS_CAPEXCHFAIL, remoteNameString);
  1577.       break;
  1578.     case H323Connection::EndedByNoAccept :
  1579.     case H323Connection::EndedByCallForwarded :
  1580.       return; // This is a call busy or forwarded, don't do SetCallMode()
  1581.     case H323Connection::EndedByAnswerDenied :
  1582.       OutputStatus(IDS_DECLINED, remoteNameString);
  1583.       break;
  1584.     case H323Connection::EndedByConnectFail :
  1585.       switch (connection.GetSignallingChannel()->GetErrorNumber()) {
  1586.         case ENETUNREACH :
  1587.           OutputStatus(IDS_HOSTUNREACHABLE, remoteNameString);
  1588.           break;
  1589.         case ETIMEDOUT :
  1590.           OutputStatus(IDS_HOSTOFFLINE, remoteNameString);
  1591.           break;
  1592.         case ECONNREFUSED :
  1593.           OutputStatus(IDS_NOENDPOINT, remoteNameString);
  1594.           break;
  1595.         default :
  1596.           OutputStatus(IDS_TRANSPORTERROR, remoteNameString);
  1597.       }
  1598.       break;
  1599.     default :
  1600.       OutputStatus(IDS_HUNGUP, remoteNameString, durationString);
  1601.   }
  1602.   currentCallToken = PString();
  1603.   SetCallMode(IdleCallMode);
  1604. }
  1605. void MainWindow::OnLogicalChannel(const H323Channel & channel,
  1606.                                   unsigned txStrID,
  1607.                                   unsigned rxStrID)
  1608. {
  1609.   const H323Capability & capability = channel.GetCapability();
  1610.   PString name = capability.GetFormatName();
  1611.   PString frames;
  1612.   if (capability.IsDescendant(H323AudioCapability::Class())) {
  1613.     unsigned numFrames = channel.GetDirection() == H323Channel::IsTransmitter
  1614.           ? ((H323AudioCapability&)capability).GetTxFramesInPacket()
  1615.           : ((H323AudioCapability&)capability).GetRxFramesInPacket();
  1616.     numFrames = ((H323AudioCapability&)capability).GetTxFramesInPacket();
  1617.     frames.sprintf(" (%u frames)", numFrames);
  1618.   }
  1619.   switch (channel.GetDirection()) {
  1620.     case H323Channel::IsTransmitter :
  1621.       OutputStatus(txStrID, (const char *)name, (const char *)frames);
  1622.       break;
  1623.     case H323Channel::IsReceiver :
  1624.       OutputStatus(rxStrID, (const char *)name, (const char *)frames);
  1625.       break;
  1626.     default :
  1627.       break;
  1628.   }
  1629. }
  1630. void MainWindow::OnHandsetLifted(OpalIxJDevice & xJack)
  1631. {
  1632.   // Are making an outside line call
  1633.   if (currentCallMode == ActiveLineCallMode)
  1634.     return;
  1635.   // Have outside line call coming in
  1636.   if (currentCallMode == IncomingLineCall) {
  1637.     SetCallMode(ActiveLineCallMode);
  1638.     OutputStatus(IDS_USINGOUTSIDELINE);
  1639.     return;
  1640.   }
  1641.   // Stop the ringing
  1642.   xJack.RingLine(OpalIxJDevice::POTSLine, 0);
  1643.   // Switch audio path to the POTS phone
  1644.   xJack.EnableAudio(OpalIxJDevice::POTSLine);
  1645.   // Already in a call, or making one, just go to phone set audio
  1646.   if (currentCallMode == MakingCallMode || currentCallMode == Active323CallMode) {
  1647.     speakerButton->Enable();
  1648.     return;
  1649.   }
  1650.   // Not in call, but have remote party name so must be incoming call.
  1651.   if (currentCallMode == IncomingCallWait) {
  1652.     AcceptCallCmd();
  1653.     return;
  1654.   }
  1655.   BOOL hasLine = xJack.IsLinePresent(OpalIxJDevice::PSTNLine);
  1656.   // Must be in idle state, so bring up dialog for speed dial.
  1657.   SpeedDialSelectDlg dlg(this);
  1658.   dlg.SetPosition(0, 0, PInteractor::CentreParent, PInteractor::CentreParent);
  1659.   if (hasLine)
  1660.     dlg.speedDialList->AddString(PResourceString(IDS_OUTSIDELINE));
  1661.   for (PINDEX i = 0; i < speedDialButtons.GetSize(); i++) {
  1662.     PTextButton & button = (PTextButton &)speedDialButtons[i];
  1663.     dlg.speedDialList->AddString(psprintf("%ut", i+1) + button.GetName());
  1664.   }
  1665.   dlg.ShowAll();
  1666.   dlg.Update();
  1667.   xJack.PlayTone(OpalIxJDevice::POTSLine, OpalLineInterfaceDevice::DialTone);
  1668.   PString digits;
  1669.   while (xJack.IsLineOffHook(OpalIxJDevice::POTSLine)) {
  1670.     digits += xJack.ReadDTMF(OpalIxJDevice::POTSLine);
  1671.     if (!digits)
  1672.       xJack.StopTone(OpalIxJDevice::POTSLine);
  1673.     if (hasLine && digits == "0") {
  1674.       dlg.Hide();
  1675.       SetCallMode(ActiveLineCallMode);
  1676.       OutputStatus(IDS_USINGOUTSIDELINE);
  1677.       xJack.SetLineToLineDirect(OpalIxJDevice::POTSLine, OpalIxJDevice::PSTNLine, TRUE);
  1678.       break;
  1679.     }
  1680.     if (digits.Find('#') != P_MAX_INDEX) {
  1681.       PINDEX selection = dlg.speedDialList->GetSelection();
  1682.       if (selection == P_MAX_INDEX)
  1683.         digits = PString();
  1684.       else {
  1685.         PString str = dlg.speedDialList->GetString(selection);
  1686. dlg.Hide();
  1687.         SpeedDial(str.Mid(str.Find('t')+1));
  1688.         break;
  1689.       }
  1690.     }
  1691.     if (digits.Find('*') != P_MAX_INDEX)
  1692.       digits = PString();
  1693.     dlg.enteredDTMF->SetName(digits);
  1694.     dlg.speedDialList->SetSelection(dlg.speedDialList->FindString(digits));
  1695.     PThread::Current()->Sleep(100);
  1696.   }
  1697.   xJack.StopTone(OpalIxJDevice::POTSLine);
  1698. }
  1699. void MainWindow::OnHandsetReturned(OpalIxJDevice & xJack)
  1700. {
  1701.   xJack.StopTone(OpalIxJDevice::POTSLine);
  1702.   xJack.SetLineOnHook(OpalIxJDevice::PSTNLine);
  1703.   xJack.SetLineToLineDirect(OpalIxJDevice::POTSLine, OpalIxJDevice::PSTNLine, FALSE);
  1704.   xJack.DisableAudio(OpalIxJDevice::PSTNLine);
  1705.   if (speakerphoneSwitch) {
  1706.     OutputStatus(IDS_ONSPEAKER);
  1707.     speakerphoneSwitch = FALSE;
  1708.   }
  1709.   else
  1710.     HangupCmd();
  1711. }
  1712. ///////////////////////////////////////////////////////////////////////////////
  1713. void SpeedDialSelectDlg::OnCancel()
  1714. {
  1715.   Hide();
  1716. }
  1717. ///////////////////////////////////////////////////////////////////////////////
  1718. OpenPhoneConnection::OpenPhoneConnection(OpenPhoneEndPoint & ep,
  1719.                                          unsigned callReference,
  1720.                                          MainWindow * _mainWindow)
  1721.   : H323Connection(ep, callReference),
  1722.     myEndpoint(ep),
  1723.     mainWindow(_mainWindow)
  1724. {
  1725.   h245Tunneling = !ep.noTunneling;
  1726. }
  1727. H323Connection::AnswerCallResponse
  1728.      OpenPhoneConnection::OnAnswerCall(const PString & caller,
  1729.                                        const H323SignalPDU & /*setupPDU*/,
  1730.                                              H323SignalPDU & /*connectPDU*/)
  1731. {
  1732.   return mainWindow->OnAnswerCall(GetCallToken(), caller) ? AnswerCallNow : AnswerCallPending;
  1733. }
  1734. BOOL OpenPhoneConnection::OnAlerting(const H323SignalPDU &, const PString & user)
  1735. {
  1736.   mainWindow->OutputStatus(IDS_RINGING, (const char *)user);
  1737.   return TRUE;
  1738. }
  1739. void OpenPhoneConnection::OnSelectLogicalChannels()
  1740. {
  1741.   if (fastStartState != FastStartDisabled && myEndpoint.noFastStart)
  1742.     return;
  1743. #if ENABLE_TRANSMITTER
  1744.   H323Connection::OnSelectLogicalChannels();
  1745. #endif
  1746. }
  1747. BOOL OpenPhoneConnection::OnOpenLogicalChannel(const H245_OpenLogicalChannel & openPDU,
  1748.                                                H245_OpenLogicalChannelAck & ackPDU,
  1749.                                                unsigned & errorCode)
  1750. {
  1751. #if ENABLE_RECEIVER
  1752.   return H323Connection::OnOpenLogicalChannel(openPDU, ackPDU, errorCode);
  1753. #else
  1754.   return FALSE;
  1755. #endif
  1756. }
  1757. void OpenPhoneConnection::OnUserInputString(const PString & value)
  1758. {
  1759.   mainWindow->OutputStatus(IDS_USERINPUT, (const char *)value);
  1760. }
  1761. ///////////////////////////////////////////////////////////////////////////////
  1762. OpenPhoneEndPoint::OpenPhoneEndPoint(MainWindow * _mainWindow)
  1763.   : mainWindow(_mainWindow)
  1764. {
  1765.   phoneThread = NULL;
  1766. }
  1767. OpenPhoneEndPoint::~OpenPhoneEndPoint()
  1768. {
  1769.   CloseQuicknet();
  1770. }
  1771. BOOL OpenPhoneEndPoint::OnIncomingCall(H323Connection & connection,
  1772.                                        const H323SignalPDU &,
  1773.                                        H323SignalPDU &)
  1774. {
  1775.   PTime now;
  1776.   PString nowStr = now.AsString("w h:m a");
  1777.   if (!alwaysForwardParty) {
  1778.     mainWindow->OutputStatus(IDS_FORWARDING, (const char *)alwaysForwardParty, (const char *)nowStr);
  1779.     return !connection.ForwardCall(alwaysForwardParty);
  1780.   }
  1781.   if (mainWindow->GetCallMode() == MainWindow::IdleCallMode)
  1782.     return TRUE;
  1783.   if (busyForwardParty.IsEmpty()) {
  1784.     mainWindow->OutputStatus(IDS_IGNORINGCALL, (const char *)connection.GetRemotePartyName());
  1785.     return FALSE;
  1786.   }
  1787.   mainWindow->OutputStatus(IDS_FORWARDING, (const char *)busyForwardParty, (const char *)nowStr);
  1788.   return !connection.ForwardCall(busyForwardParty);
  1789. }
  1790. BOOL OpenPhoneEndPoint::OnConnectionForwarded(H323Connection & /*connection*/,
  1791.                                               const PString & forwardParty,
  1792.                                               const H323SignalPDU & /*pdu*/)
  1793. {
  1794.   return mainWindow->OnConnectionForwarded(forwardParty);
  1795. }
  1796. void OpenPhoneEndPoint::OnConnectionEstablished(H323Connection & connection,
  1797.                                                 const PString & token)
  1798. {
  1799.   xJack.StopTone(OpalIxJDevice::POTSLine);
  1800.   mainWindow->OnConnectionEstablished(token, connection.GetRemotePartyName());
  1801. }
  1802. void OpenPhoneEndPoint::OnConnectionCleared(H323Connection & connection, const PString &)
  1803. {
  1804.   xJack.RingLine(OpalIxJDevice::POTSLine, 0);
  1805.   mainWindow->OnConnectionCleared(connection);
  1806.   if (xJack.IsLineOffHook(OpalIxJDevice::POTSLine))
  1807.     xJack.PlayTone(OpalIxJDevice::POTSLine, OpalLineInterfaceDevice::BusyTone);
  1808.   else
  1809.     xJack.StopTone(OpalIxJDevice::POTSLine);
  1810. }
  1811. H323Connection * OpenPhoneEndPoint::CreateConnection(unsigned callReference)
  1812. {
  1813.   return new OpenPhoneConnection(*this, callReference, mainWindow);
  1814. }
  1815. BOOL OpenPhoneEndPoint::OpenAudioChannel(H323Connection & connection,
  1816.                                          BOOL isEncoding,
  1817.                                          unsigned bufferSize,
  1818.                                          H323AudioCodec & codec)
  1819. {
  1820.   codec.SetSilenceDetectionMode(silenceDetect ? H323AudioCodec::AdaptiveSilenceDetection
  1821.                                               : H323AudioCodec::NoSilenceDetection);
  1822.   if (xJack.IsOpen()) {
  1823.     PTRACE(2, "xJacktAttaching channel to codec");
  1824.     return codec.AttachChannel(new OpalLineChannel(xJack, OpalIxJDevice::POTSLine, isEncoding));
  1825.   }
  1826.   return H323EndPoint::OpenAudioChannel(connection, isEncoding, bufferSize, codec);
  1827. }
  1828. BOOL OpenPhoneEndPoint::OpenVideoDevice(H323Connection & connection,
  1829.                                         BOOL isEncoding,
  1830.                                         H323VideoCodec & codec)
  1831. {
  1832.   H323VideoDevice * channel = new VideoDevice(mainWindow, isEncoding,
  1833.                isEncoding ? GetLocalUserName() : connection.GetRemotePartyName());
  1834.   if (isEncoding) {
  1835.     PConfig config;
  1836.     codec.SetVideoInput(config.GetInteger(VideoSourceConfigKey, 1));
  1837.     codec.SetVideoFormat(config.GetInteger(VideoFormatConfigKey, 1) != 0);
  1838.     channel->SetSize(352>>(3-videoSize), 288>>(3-videoSize));
  1839.   }
  1840.   return codec.AttachDevice(channel);
  1841. }
  1842. BOOL OpenPhoneEndPoint::OnStartLogicalChannel(H323Connection &, H323Channel & channel)
  1843. {
  1844.   mainWindow->OnLogicalChannel(channel, IDS_STARTCHANNELTX, IDS_STARTCHANNELRX);
  1845.   return TRUE;
  1846. }
  1847. void OpenPhoneEndPoint::OnClosedLogicalChannel(H323Connection &, const H323Channel & channel)
  1848. {
  1849.   mainWindow->OnLogicalChannel(channel, IDS_STOPCHANNELTX, IDS_STOPCHANNELRX);
  1850. }
  1851. static void UpdateField(PStaticText * field, DWORD value)
  1852. {
  1853.   field->SetName(psprintf("%u", value));
  1854. }
  1855. void OpenPhoneEndPoint::OnRTPStatistics(const H323Connection & connection,
  1856.                                         const RTP_Session & session) const
  1857. {
  1858.   StatisticsDlg & dlg = *mainWindow->statisticsDialog;
  1859.   UpdateField(dlg.packetsSent, session.GetPacketsSent());
  1860.   UpdateField(dlg.octetsSent, session.GetOctetsSent());
  1861.   UpdateField(dlg.packetsReceived, session.GetPacketsReceived());
  1862.   UpdateField(dlg.octetsReceived, session.GetOctetsReceived());
  1863.   UpdateField(dlg.packetsLost, session.GetPacketsLost());
  1864.   UpdateField(dlg.packetsTooLate, session.GetPacketsTooLate());
  1865.   UpdateField(dlg.packetsOutOfOrder, session.GetPacketsOutOfOrder());
  1866.   UpdateField(dlg.averageSendTime, session.GetAverageSendTime());
  1867.   UpdateField(dlg.maximumSendTime, session.GetMaximumSendTime());
  1868.   UpdateField(dlg.minimumSendTime, session.GetMinimumSendTime());
  1869.   UpdateField(dlg.averageReceiveTime, session.GetAverageReceiveTime());
  1870.   UpdateField(dlg.maximumReceiveTime, session.GetMaximumReceiveTime());
  1871.   UpdateField(dlg.minimumReceiveTime, session.GetMinimumReceiveTime());
  1872.   UpdateField(dlg.roundTripDelay, connection.GetRoundTripDelay().GetInterval());
  1873.   PStringStream duration;
  1874.   duration << setprecision(0) << setw(5)
  1875.            << (PTime() - connection.GetConnectionStartTime());
  1876.   dlg.callDuration->SetName(duration);
  1877. }
  1878. BOOL OpenPhoneEndPoint::Initialise(PConfig & config)
  1879. {
  1880.   SetLocalUserName(config.GetString(UsernameConfigKey, GetLocalUserName()));
  1881.   PINDEX i = 0;
  1882.   PString alias;
  1883.   while (!(alias = config.GetString(psprintf(AliasConfigKey, i++))))
  1884.     AddAliasName(alias);
  1885.   SetInitialBandwidth((unsigned)(config.GetReal(BandwidthConfigKey, 10000)*20));
  1886.   SetMaxAudioDelayJitter(config.GetInteger(JitterConfigKey,
  1887.                                             GetInitialBandwidth() < 10000 ? 120 : 50));
  1888.   SetRtpIpTypeofService(config.GetInteger(IpTosConfigKey, GetRtpIpTypeofService()));
  1889.   noFastStart = config.GetBoolean(NoFastStartConfigKey, FALSE);
  1890.   noTunneling = config.GetBoolean(NoTunnelingConfigKey, FALSE);
  1891.   silenceDetect = config.GetBoolean(SilenceDetectConfigKey, TRUE);
  1892.   alwaysForwardParty = config.GetString(AlwaysForwardPartyConfigKey);
  1893.   busyForwardParty = config.GetString(BusyForwardPartyConfigKey);
  1894.   videoSize = config.GetInteger(VideoSizeConfigKey, 1);
  1895.   autoStartTransmitVideo = videoSize > 1;
  1896.   autoStartReceiveVideo = config.GetBoolean(AutoReceiveVideoConfigKey, TRUE);
  1897.   // set record and play devices
  1898.   SetSoundChannelPlayDevice  (config.GetString(SoundPlayConfigKey,   GetSoundChannelPlayDevice()));
  1899.   SetSoundChannelRecordDevice(config.GetString(SoundRecordConfigKey, GetSoundChannelRecordDevice()));
  1900.   SetSoundChannelBufferDepth(config.GetInteger(SoundBuffersConfigKey, GetSoundChannelBufferDepth()));
  1901.   OpenQuicknet(config);
  1902.   LoadCapabilities(config);
  1903.   // start the H323 stack listening for incoming calls
  1904.   H323ListenerTCP * listener = new H323ListenerTCP(*this);
  1905.   if (StartListener(listener))
  1906.     return FindGatekeeper(config);
  1907.   PSimpleDialog::Error(mainWindow, IDS_NOPORT, listener->GetListenerPort());
  1908.   return FALSE;
  1909. }
  1910. BOOL OpenPhoneEndPoint::OpenQuicknet(PConfig & config)
  1911. {
  1912.   PStringArray devices = OpalIxJDevice::GetDeviceNames();
  1913.   if (!config.GetBoolean(UseQuicknetConfigKey, devices.GetSize() > 0))
  1914.     return FALSE;
  1915.   PString device = config.GetString(QuicknetDeviceConfigKey, devices[0]);
  1916.   if (xJack.GetName() == device)
  1917.     return TRUE;
  1918.   InitialiseQuicknetDlg dlg(mainWindow);
  1919.   dlg.SetPosition(0, 0, PInteractor::CentreParent, PInteractor::CentreParent);
  1920.   dlg.ShowAll();
  1921.   dlg.Update();
  1922.   CloseQuicknet();
  1923.   if (!xJack.Open(device)) {
  1924.     PSimpleDialog::Error(mainWindow, IDS_XJACKOPENFAIL, (const char *)device);
  1925.     return FALSE;
  1926.   }
  1927.   xJack.SetLineToLineDirect(OpalIxJDevice::POTSLine, OpalIxJDevice::PSTNLine, FALSE);
  1928.   xJack.IsLinePresent(OpalIxJDevice::PSTNLine);
  1929.   xJack.DisableAudio(OpalIxJDevice::POTSLine);
  1930.   xJack.SetAEC(OpalIxJDevice::POTSLine,
  1931.                (OpalIxJDevice::AECLevels)config.GetInteger(AECConfigKey, OpalIxJDevice::AECMedium));
  1932.   phoneThread = new QuicknetThread(mainWindow, xJack);
  1933.   return TRUE;
  1934. }
  1935. void OpenPhoneEndPoint::CloseQuicknet()
  1936. {
  1937.   xJack.Close();
  1938.   if (phoneThread != NULL) {
  1939.     phoneThread->WaitForTermination();
  1940.     delete phoneThread;
  1941.     phoneThread = NULL;
  1942.   }
  1943. }
  1944. BOOL OpenPhoneEndPoint::FindGatekeeper(PConfig & config)
  1945. {
  1946.   if (GetGatekeeper() != NULL)
  1947.     mainWindow->OutputStatus(IDS_UNREGGK, (const char *)GetGatekeeper()->GetName());
  1948.   if (!config.GetBoolean(UseGatekeeperConfigKey, FALSE)) {
  1949.     RemoveGatekeeper();
  1950.     return TRUE;
  1951.   }
  1952.   PString host = config.GetString(GatekeeperHostConfigKey);
  1953.   DiscoverGatekeeperDlg dlg(mainWindow);
  1954.   dlg.SetPosition(0, 0, PInteractor::CentreParent, PInteractor::CentreParent);
  1955.   dlg.ShowAll();
  1956.   dlg.Update();
  1957.   BOOL found;
  1958.   if (host.IsEmpty())
  1959.     found = DiscoverGatekeeper();
  1960.   else
  1961.     found = SetGatekeeper(host);
  1962.   if (found) {
  1963.     mainWindow->OutputStatus(IDS_USINGGK, (const char *)GetGatekeeper()->GetName());
  1964.     return TRUE;
  1965.   }
  1966.   if (!config.GetBoolean(RequireGatekeeperConfigKey, FALSE))
  1967.     return TRUE;
  1968.   PSimpleDialog::Error(mainWindow, IDS_NOGATEKEEPER);
  1969.   return FALSE;
  1970. }
  1971. void OpenPhoneEndPoint::LoadCapabilities(PConfig & config)
  1972. {
  1973.   PINDEX i;
  1974.   capabilities.RemoveAll();
  1975.   // Add all the codecs we know about
  1976.   if (xJack.IsOpen())
  1977.     H323_LIDCapability::AddAllCapabilities(xJack, capabilities, 0, 0);
  1978. #ifdef WIN32
  1979.   H323_ACMG7231Capability * acmG7231 = new H323_ACMG7231Capability();
  1980.   if (acmG7231->IsValid())
  1981.     SetCapability(0, 0, acmG7231);
  1982.   else
  1983.     delete acmG7231;
  1984. #endif
  1985.   SetCapability(0, 0, new H323_LPC10Capability(*this));
  1986.   SetCapability(0, 0, new H323_GSM0610Capability);
  1987.   SetCapability(0, 0, new H323_G711Capability(H323_G711Capability::muLaw));
  1988.   SetCapability(0, 0, new H323_G711Capability(H323_G711Capability::ALaw));
  1989.   // Now get all of the codec names we have remembered in PConfig
  1990.   PStringArray enabledCodecs;
  1991.   PStringArray disabledCodecs;
  1992.   PINDEX codecNum = 0;
  1993.   for (;;) {
  1994.     PString key = psprintf(CodecsConfigKey, ++codecNum);
  1995.     PString name = config.GetString(CodecsConfigSection, key, "");
  1996.     if (name.IsEmpty())
  1997.       break;
  1998.     BOOL needRewrite = FALSE;
  1999.     PINDEX suffixPos = name.Find(OffCodecSuffix);
  2000.     if (suffixPos != P_MAX_INDEX)
  2001.       disabledCodecs[disabledCodecs.GetSize()] = name(0, suffixPos-1);
  2002.     else {
  2003.       PString enabledCodecName;
  2004.       suffixPos = name.Find(OnCodecSuffix);
  2005.       if (suffixPos != P_MAX_INDEX)
  2006.         enabledCodecName = name.Left(suffixPos);
  2007.       else {
  2008.         // Compatibility with old entries, remove the <num> and add (On).
  2009.         if (name[name.GetLength()-1] == '>') {
  2010.           PINDEX pos = name.FindLast('<');
  2011.           if (name[pos-1] == ' ')
  2012.             pos--;
  2013.           name.Delete(pos, P_MAX_INDEX);
  2014.           name += OnCodecSuffix;
  2015.           needRewrite = TRUE;
  2016.         }
  2017.       }
  2018.       enabledCodecs[enabledCodecs.GetSize()] = enabledCodecName;
  2019.     }
  2020.     // See if codec is physically available, disable if not
  2021.     BOOL notPhysical = TRUE;
  2022.     for (i = 0; i < capabilities.GetSize(); i++) {
  2023.       if (name.Find(capabilities[i].GetFormatName()) == 0) {
  2024.         notPhysical = FALSE;
  2025.         unsigned txFrames = 0;
  2026.         PINDEX left = name.FindLast('[');
  2027.         PINDEX right = name.FindLast(']');
  2028.         if (left != P_MAX_INDEX && right != P_MAX_INDEX)
  2029.           txFrames = name(left+1, right-1).AsUnsigned();
  2030.         if (txFrames > 0 && txFrames < 100)
  2031.           capabilities[i].SetTxFramesInPacket(txFrames);
  2032.         else {
  2033.           name.sprintf(" [%u]", capabilities[i].GetTxFramesInPacket());
  2034.           needRewrite = TRUE;
  2035.         }
  2036.         break;
  2037.       }
  2038.     }
  2039.     if (notPhysical) {
  2040.       name.Replace(OnCodecSuffix, OffCodecSuffix);
  2041.       needRewrite = TRUE;
  2042.     }
  2043.     if (needRewrite)
  2044.       config.SetString(CodecsConfigSection, key, name);
  2045.   }
  2046.   // Remove all of the disabled codecs
  2047.   for (i = 0; i < disabledCodecs.GetSize(); i++)
  2048.     capabilities.Remove(disabledCodecs[i]);
  2049.   // Now go through the list of real codecs and add missing entries to PConfig
  2050.   for (i = 0; i < capabilities.GetSize(); i++) {
  2051.     PString realCodec = capabilities[i].GetFormatName();
  2052.     if (enabledCodecs.GetValuesIndex(realCodec) == P_MAX_INDEX)
  2053.       config.SetString(CodecsConfigSection,
  2054.                        psprintf(CodecsConfigKey, codecNum++),
  2055.                        psprintf("%s%s [%u]",
  2056.                                 (const char *)realCodec,
  2057.                                 OnCodecSuffix,
  2058.                                 capabilities[i].GetTxFramesInPacket()));
  2059.   }
  2060.   // Reorder the codecs we have
  2061.   capabilities.Reorder(enabledCodecs);
  2062.   unsigned qcif = config.GetBoolean(H261QCIFConfigKey, TRUE) ? 1 : 0;
  2063.   unsigned cif = config.GetBoolean(H261CIFConfigKey, TRUE) ? 2 : 0;
  2064.   if (qcif > 0 || cif > 0)
  2065.     SetCapability(0, P_MAX_INDEX, new H323_H261Capability(qcif, cif));
  2066.   SetCapability(0, P_MAX_INDEX, new H323_UserInputCapability);
  2067.   //SetCapability(0, P_MAX_INDEX, new H323_T120Capability);
  2068.   PTRACE(1, "CodectCapability Table:n" << setprecision(4) << capabilities);
  2069. }
  2070. ///////////////////////////////////////////////////////////////////////////////
  2071. QuicknetThread::QuicknetThread(MainWindow * wnd, OpalIxJDevice & jack)
  2072.   : PThread(10000, NoAutoDeleteThread),
  2073.     mainWindow(wnd),
  2074.     xJack(jack)
  2075. {
  2076.   Resume();
  2077. }
  2078. void QuicknetThread::Main()
  2079. {
  2080.   PTRACE(3, "xJacktStarted hook monitor thread");
  2081.   while (xJack.IsOpen()) {
  2082.     switch (mainWindow->GetCallMode()) {
  2083.       case MainWindow::IdleCallMode :
  2084.         if (xJack.IsLineRinging(OpalIxJDevice::PSTNLine)) {
  2085.           PString callerID;
  2086.           if (xJack.GetCallerID(OpalIxJDevice::PSTNLine, callerID))
  2087.             mainWindow->OutputStatus(IDS_CALLERID, (const char *)callerID);
  2088.           else
  2089.             mainWindow->OutputStatus(IDS_LINERINGING);
  2090.           mainWindow->SetCallMode(MainWindow::IncomingLineCall);
  2091.           xJack.SetLineToLineDirect(OpalIxJDevice::POTSLine, OpalIxJDevice::PSTNLine, TRUE);
  2092.         }
  2093.         break;
  2094.       case MainWindow::IncomingLineCall :
  2095.         if (!xJack.IsLineRinging(OpalIxJDevice::PSTNLine)) {
  2096.           xJack.SetLineToLineDirect(OpalIxJDevice::POTSLine, OpalIxJDevice::PSTNLine, FALSE);
  2097.           mainWindow->OutputStatus(IDS_CALLDISAPPEARED);
  2098.           mainWindow->SetCallMode(MainWindow::IdleCallMode);
  2099.         }
  2100.         break;
  2101.       case MainWindow::ApplicationShuttingDown :
  2102.         return;
  2103.       default :
  2104.         break;
  2105.     }
  2106.     if (xJack.IsLineOffHook(OpalIxJDevice::POTSLine)) {
  2107.       PTRACE(3, "xJacktHandset lifted");
  2108.       mainWindow->OnHandsetLifted(xJack);
  2109.       while (xJack.IsLineOffHook(OpalIxJDevice::POTSLine))
  2110.         PThread::Current()->Sleep(500);
  2111.       mainWindow->OnHandsetReturned(xJack);
  2112.       PTRACE(3, "xJacktRestarted hook monitor thread");
  2113.     }
  2114.     Sleep(100);
  2115.   }
  2116. }
  2117. ///////////////////////////////////////////////////////////////////////////////
  2118. VideoWindow::VideoWindow(PInteractor * parent, VideoDevice * dev, BOOL local)
  2119.   : PFloatingDialog(parent)
  2120. {
  2121.   device = dev;
  2122.   localVideo = local;
  2123.   canvas = NULL;
  2124. }
  2125. VideoWindow::~VideoWindow()
  2126. {
  2127.   // Release the mutex and request it again, this guarantees that if the video
  2128.   // thread happens to be in the mutex wait in WriteLineSegment() it is executed
  2129.   // and exited from that function before continuing out of the shutdown procedure.
  2130.   mutex.Wait();
  2131.   delete canvas;
  2132. }
  2133. void VideoWindow::OnClose()
  2134. {
  2135.   Shutdown();
  2136.   PConfig config;
  2137.   PPoint pos = GetPosition(PixelCoords);
  2138.   config.SetInteger(localVideo ? LocalVideoWindowLeftConfigKey
  2139.                                : RemoteVideoWindowLeftConfigKey, pos.X());
  2140.   config.SetInteger(localVideo ? LocalVideoWindowTopConfigKey
  2141.                                : RemoteVideoWindowTopConfigKey, pos.Y());
  2142.   PFloatingDialog::OnClose();
  2143. }
  2144. void VideoWindow::OnCancel()
  2145. {
  2146.   Shutdown();
  2147.   Close();
  2148. }
  2149. void VideoWindow::OnRedraw(PCanvas & redrawCanvas)
  2150. {
  2151.   if (!image.IsNULL())
  2152.     redrawCanvas.DrawPixels(0, 0, image);
  2153.   // We create canvas in here as under Win32 we must have the construction AND
  2154.   // destruction of a canvas in the "GUI" thread.
  2155.   if (canvas == NULL) {
  2156.     canvas = new PDrawCanvas(this);
  2157.     canvas->SetViewportRect(canvas->GetMappingRect());
  2158.   }
  2159. }
  2160. void VideoWindow::SetVideoSize(int width, int height)
  2161. {
  2162.   SetDimensions(width, height, PixelCoords);
  2163.   if (image.IsNULL()) {
  2164.     image = PPixelImage(width, height, 24);
  2165.     raster = PPixelImage(width, 1, 24);
  2166.   }
  2167.   PConfig config;
  2168.   PORDINATE x = config.GetInteger(localVideo ? LocalVideoWindowLeftConfigKey
  2169.                                              : RemoteVideoWindowLeftConfigKey,
  2170.                                   localVideo ? 0 : 300);
  2171.   PORDINATE y = config.GetInteger(localVideo ? LocalVideoWindowTopConfigKey
  2172.                                              : RemoteVideoWindowTopConfigKey,
  2173.                                   GetParent()->GetDimensions(PixelCoords).Height());
  2174.   SetPosition(x, y, TopLeftPixels, TopLeftPixels);
  2175.   Show();
  2176. }
  2177. BOOL VideoWindow::WriteLineSegment(int x, int y, unsigned len, const BYTE * data)
  2178. {
  2179.   PWaitAndSignal wait(mutex);
  2180.   if (device == NULL || image.IsNULL())
  2181.     return FALSE;
  2182.   memcpy(image->GetRasterDataPtr(y)+x*3, data, len*3);
  2183.   if (canvas == NULL)
  2184.     Invalidate();
  2185.   else {
  2186.     memcpy(raster->GetRasterDataPtr(0), image->GetRasterDataPtr(y), image->GetDimensions().Width()*3);
  2187.     canvas->DrawPixels(0, y, raster);
  2188.   }
  2189.   return TRUE;
  2190. }
  2191. void VideoWindow::Shutdown()
  2192. {
  2193.   mutex.Wait();
  2194.   if (device != NULL) {
  2195.     device->windowOpen = FALSE;
  2196.     device = NULL;
  2197.   }
  2198.   mutex.Signal();
  2199. }
  2200. ///////////////////////////////////////////////////////////////////////////////
  2201. VideoDevice::VideoDevice(MainWindow * mainWindow, BOOL local, const PString & title)
  2202. {
  2203.   window = new VideoWindow(mainWindow, this, local);
  2204.   window->SetTitle(title);
  2205.   windowOpen = TRUE;
  2206.   rgbReverseOrder = TRUE;
  2207. }
  2208. VideoDevice::~VideoDevice()
  2209. {
  2210.   if (windowOpen)
  2211.     window->OnCancel();
  2212. }
  2213. void VideoDevice::SetSize(int w, int h)
  2214. {
  2215.   H323VideoDevice::SetSize(w, h);
  2216.   if (windowOpen)
  2217.     window->SetVideoSize(width, height);
  2218. }
  2219. BOOL VideoDevice::WriteLineSegment(int x, int y, unsigned len, const BYTE * data)
  2220. {
  2221.   if (windowOpen)
  2222.     return window->WriteLineSegment(x, y, len, data);
  2223.   return FALSE;
  2224. }
  2225. // End of File ///////////////////////////////////////////////////////////////