callermain.cxx
上传用户:wzkunzhan
上传日期:2022-04-23
资源大小:2618k
文件大小:41k
源码类别:

模拟服务器

开发平台:

Visual C++

  1. /*
  2.  * main.cxx
  3.  *
  4.  * Main source for for OpenAM
  5.  *
  6.  * A H.323 answering machine application.
  7.  *
  8.  * Copyright (c) 1993-2001 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 Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  */
  28. #include <ptlib.h>
  29. #include <ptlib/pipechan.h>
  30. #include "version.h"
  31. #include "lpc10codec.h"
  32. #include "speexcodec.h"
  33. #include "mscodecs.h"
  34. #include "opalvxml.h"
  35. #include "callermain.h"
  36. //PCREATE_PROCESS(Caller);
  37. #define new PNEW
  38. #define DEFAULT_MSG_LIMIT 30
  39. #define DEFAULT_CALL_LOG "call_log.txt"
  40. #define G7231_SAMPLES_PER_BLOCK 240
  41. #define CHECK_PCM   1
  42. #define CHECK_G7231 2
  43. #define MENU_PREFIX "UserMenu-"
  44. static PMutex logMutex;
  45. static PTextFile logFile;
  46. static PFilePath logFilename = DEFAULT_CALL_LOG;
  47. extern PString G7231Ext;
  48. extern PString WAVExt;
  49. extern PString PCMExt;
  50. extern BOOL CheckWAVFileValid(PWAVFile *chan, int type);
  51. static void LogMessage(const PString & str)
  52. {
  53.   PTime now;
  54.   PString msg = now.AsString("hh:mm:ss dd/MM/yyyy") & str;
  55.   logMutex.Wait();
  56.   if (!logFile.IsOpen()) {
  57.     logFile.Open(logFilename, PFile::ReadWrite);
  58.     logFile.SetPosition(0, PFile::End);
  59.   }
  60.   logFile.WriteLine(msg);
  61.   logFile.Close();
  62.   
  63.   logMutex.Signal();
  64. }
  65. static void LogCall(const PFilePath & fn,
  66.                     const PString & from,
  67.                     const PString & user,
  68.                     unsigned len,
  69.                     const PString & codec,
  70.                     const PString & product)
  71. {
  72.   PString addr = from;
  73.   LogMessage(addr & """ + user + """ & PString(PString::Unsigned, len) & codec & """ + product + """ & """ + fn + """);
  74. }
  75. ///////////////////////////////////////////////////////////////
  76. /*
  77. Caller::Caller()
  78.   : PProcess("NCE VOIP Project", "Caller",
  79.              MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
  80. {
  81. }
  82. */
  83. Caller::Caller()
  84.   : PObject()
  85. {
  86. }
  87. Caller::~Caller()
  88. {
  89. }
  90. void Caller::CallerMain(PString Cargs)
  91. {
  92.  // cout << GetName()
  93.  //      << " Version " << GetVersion(TRUE)
  94.  //      << " by " << GetManufacturer()
  95.  //      << " on " << GetOSClass() << ' ' << GetOSName()
  96.  //      << " (" << GetOSVersion() << '-' << GetOSHardware() << ")nn";
  97. // cout <<"Inside the Caller..n";
  98.   //PConfigArgs args(GetArguments());
  99.    PConfigArgs args(Cargs);
  100.   args.Parse(
  101.              "D-disable:"
  102.              "d-directory:"
  103.              "g-gatekeeper:"         "n-no-gatekeeper."
  104.              "-g711-ulaw."           "-no-g711-ulaw."
  105.              "-g711-alaw."           "-no-g711-alaw."
  106.              "-g711message:"         "-no-g711message."
  107.              "-g7231."               "-no-g7231."
  108.              "-g7231message:"        "-no-g7231message."
  109.              "-gsm."                 "-no-gsm."
  110.              "-gsmmessage:"          "-no-gsmmessage."
  111.              "h-help."
  112.              "H-hangup."             "-no-hangup."
  113.              "i-interface:"          "-no-interface."
  114.              "k-kill."               "-no-kill."
  115.              "l-limit:"              "-no-limit."
  116.              "-listenport:"          "-no-listenport."
  117.              "-lpc10message:"        "-no-lpc10message."
  118.              "-speexmessage:"        "-no-speexmessage."
  119.              "m-message:"            "-no-message."
  120.              "-no-recordg7231."
  121. #if PTRACING
  122.              "o-output:"
  123. #endif
  124.              "P-prefer:"
  125.              "-pcm."                 "-no-pcm."
  126.              "-pcmmessage:"          "-no-pcmmessage."
  127.              "-port:"
  128.              "q-quicknet:"           "-no-quicknet:"
  129.              "r-run:"                "-no-run."
  130.      "-recordraw."
  131.              "-require-gatekeeper."  "-no-require-gatekeeper."
  132.              "-save."
  133. #if PMEMORY_CHECK
  134.              "-setallocationbreakpoint:"
  135. #endif
  136. #if PTRACING
  137.              "t-trace."
  138. #endif
  139.      "u-username:"           "-no-username."
  140.           , FALSE);
  141. #if PMEMORY_CHECK
  142.   if (args.HasOption("setallocationbreakpoint"))
  143.     PMemoryHeap::SetAllocationBreakpoint(args.GetOptionString("setallocationbreakpoint").AsInteger());
  144. #endif
  145. #if PTRACING
  146.   PTrace::Initialise(args.GetOptionCount('t'),
  147.                      args.HasOption('o') ? (const char *)args.GetOptionString('o') : NULL);
  148. #endif
  149.   if (args.HasOption('h')) {
  150.     cout << "Usage : " << "-d"<< " [options]n"
  151.             "Options:n"
  152.             "  -d --directory dir  : Put recorded mesages into dirn"
  153.             "  -l --limit secs     : Limit recorded messages to secs duration (default " << DEFAULT_MSG_LIMIT << ")n"
  154.             "  -m --pcmmessage fn  : Set outgoing message for PCM derived codecs (G.711/GSM) to fnn"
  155.             "  --g7231message fn   : Set outgoing message for G723.1 codec to fnn"
  156.             "  --g711message fn    : Set outgoing message for G711 codec to fnn"
  157.             "  --gsmmessage fn     : Set outgoing message for GSM codec to fnn"
  158.             "  --lpc10message fn   : Set outgoing message for LPC10 codec to fnn"
  159.             "  --speexmessage fn   : Set outgoing message for Speex codec to fnn"
  160.             "  --recordraw         : Record PCM audo in raw files (.sw) instead of .wavn"
  161.             "  -r --run cmd        : Run this command after each recorded messagen"
  162.             "  -k --kill           : Kill recorded files after user commandn"
  163.             "  -H --hangup         : hangup after playing messagen"
  164.             "  -u --username str   : Set the local endpoint name to strn"
  165.             "  -i --interface ip   : Bind to a specific interfacen"
  166.             "  --listenport port   : Listen on a specific portn"
  167.             "  -g --gatekeeper host: Specify gatekeeper host.n"
  168.             "  -n --no-gatekeeper  : Disable gatekeeper discovery.n"
  169.             "  --require-gatekeeper: Exit if gatekeeper discovery fails.n"
  170.             "  -D --disable codec  : Disable the specified codec (may be used multiple times)n"
  171.             "  -P --prefer codec   : Prefer the specified codec (may be used multiple times)n"
  172. #if PTRACING
  173.             "  -t --trace          : Enable trace, use multiple times for more detailn"
  174.             "  -o --output         : File for trace output, default is stderrn"
  175. #endif
  176.             "     --save           : Save arguments in configuration filen"
  177.             "  -h --help           : Display this help messagen";
  178.     return;
  179.   }
  180.   args.Save("save");
  181. #if HAS_IXJ
  182.   if (args.GetCount() > 0) {
  183.     if (args[0] *= "record") 
  184.       RecordFile(args);    
  185.     else if (args[0] *= "play") 
  186.       PlayFile(args);
  187.     else {
  188. //cout << "No Command -> assuming destination address." << endl;
  189. }
  190. //      cerr << "unknown command "" << args[0] << """ << endl;
  191. //    return;
  192.   }
  193. #endif
  194.   unsigned callLimit = DEFAULT_MSG_LIMIT;
  195.   if (args.HasOption('l')) {
  196.     callLimit = args.GetOptionString('l').AsInteger();
  197.     if (callLimit > 3600) {
  198.       cout << "warning: maximum call length " << callLimit << " is out of range. Using " << DEFAULT_MSG_LIMIT << " insteadn";
  199.       callLimit = DEFAULT_MSG_LIMIT;
  200.     } else if (callLimit == 0)
  201.       cout << "warning: recorded message call limit disabledn";
  202.   }
  203.  // cout << "Recorded messages limited to " << callLimit << " secondsn";
  204. cout <<"Duration of the test session is expected to be approximately 3-5 minutes. nPlease Be Patient...n";
  205.   PString runCmd;
  206.   if (args.HasOption('r')) {
  207.     runCmd = args.GetOptionString('r');
  208.     cout << "Executing "" << runCmd << "" after each message" << endl;
  209.   }
  210.   PDirectory dir;
  211.   if (args.HasOption('d'))
  212.     dir = args.GetOptionString('d');
  213.   int flags = 0;
  214.   if (args.HasOption("no-recordg7231")) {
  215.     cout << "Supressing recording of G723.1 messages" << endl;
  216.     flags |= C_MyH323EndPoint::NoRecordG7231;
  217.   }
  218.   if (args.HasOption('k')) {
  219.     cout << "Deleting recorded files after processing" << endl;
  220.     if (runCmd.IsEmpty()) 
  221.       cout << "WARNING: recorded files will be deleted even though no run command is present" << endl;
  222.     flags |= C_MyH323EndPoint::DeleteAfterRecord;
  223.   }
  224.   if (args.HasOption('H'))
  225.     flags |= C_MyH323EndPoint::HangupAfterPlay;
  226.   
  227. //  cout<<"before endpointn";
  228.   C_MyH323EndPoint endpoint(callLimit, runCmd, dir, flags);
  229. //  cout<<"After endpointn";
  230.  /* PString userName = "OpenH323 Answering Machine v" + GetVersion();
  231.   if (args.HasOption('u'))
  232.     userName = args.GetOptionString('u');
  233.   endpoint.SetLocalUserName(userName);*/
  234.   if (!endpoint.Initialise(args))
  235.     return;
  236.   // start the H.323 listener
  237. /* Codigo retirado do Openam para implementacao do Caller
  238.   H323ListenerTCP * listener;
  239.   PIPSocket::Address interfaceAddress(INADDR_ANY);
  240.   WORD listenPort = H323EndPoint::DefaultTcpPort;
  241.   if (args.HasOption("listenport"))
  242.     listenPort = (WORD)args.GetOptionString("listenport").AsInteger();
  243.   if (args.HasOption('i'))
  244.     interfaceAddress = PIPSocket::Address(args.GetOptionString('i'));
  245.   listener  = new H323ListenerTCP(endpoint, interfaceAddress, listenPort);
  246.   if (!endpoint.StartListener(listener)) {
  247.     cout <<  "Could not open H.323 listener port on "
  248.          << listener->GetListenerPort() << endl;
  249.     delete listener;
  250.     return;
  251.   }
  252. */
  253.   if (args.HasOption('g')) {
  254.     PString gkName = args.GetOptionString('g');
  255.     if (endpoint.SetGatekeeper(gkName, new H323TransportUDP(endpoint)))
  256.       cout << "Gatekeeper set: " << *endpoint.GetGatekeeper() << endl;
  257.     else {
  258.       cout << "Error registering with gatekeeper at "" << gkName << '"' << endl;
  259.       return;
  260.     }
  261.   }
  262.  /* else if (!args.HasOption('n')) {
  263.     cout << "Searching for gatekeeper..." << flush;
  264.     if (endpoint.DiscoverGatekeeper(new H323TransportUDP(endpoint)))
  265.       cout << "nGatekeeper found: " << *endpoint.GetGatekeeper() << endl;
  266.     else {
  267.       cout << "nNo gatekeeper found." << endl;
  268.       if (args.HasOption("require-gatekeeper"))
  269.         return;
  270.     }
  271.   }*/
  272. /*
  273.   cout << "Waiting for incoming calls for "" << endpoint.GetLocalUserName() << '"' << endl;
  274.   for (;;) 
  275.     PThread::Current()->Sleep(5000);
  276. */
  277.   if (endpoint.MakeOutgoingCall(args[0])) {
  278.           endpoint.AwaitTermination();
  279.   } else {
  280.           cout << "Sorry, Exiting..." << endl;
  281.           return;
  282.   }
  283. }
  284. ///////////////////////////////////////////////////////////////
  285. C_MyH323EndPoint::C_MyH323EndPoint(unsigned _callLimit,
  286.                                const PString & _runCmd,
  287.                                const PDirectory & _dir,
  288.                                int   _flags)
  289.   : callLimit(_callLimit), runCmd(_runCmd), dir(_dir), flags(_flags)
  290. {
  291. }
  292. // Caller - Novos Metodos - Cesar
  293. BOOL C_MyH323EndPoint::OnAlerting( H323Connection & _conn, const H323SignalPDU & _SPDU, const PString & _user)
  294. {
  295.         cout << "  Ringing to " << _user << endl;
  296.         return TRUE;
  297. }
  298. void C_MyH323EndPoint::OnConnectionEstablished( H323Connection & _conn , const PString & _token  )
  299. {
  300.   C_MyH323Connection & conn = (C_MyH323Connection &)_conn;
  301.   RTP_Session * session = conn.GetSession(RTP_Session::DefaultAudioSessionID);
  302.   session->SetReportTimeInterval(1000);
  303.   StateFlag=InCall;
  304. }
  305. void C_MyH323EndPoint::OnConnectionCleared( H323Connection & _conn, const PString & _token )
  306. {
  307.         StateFlag=CallClosed;
  308. }
  309. void C_MyH323EndPoint::AwaitTermination()
  310. {
  311.         for (;;)
  312.         {
  313.                 if (StateFlag!=CallClosed) PThread::Current()->Sleep(5000);
  314.                 else break;
  315.         }
  316. }
  317. BOOL  C_MyH323EndPoint::MakeOutgoingCall(const PString & _dest)
  318. {
  319.         PString fullAddress;
  320. //      WORD CallPort = H323ListenerTCP::DefaultSignalPort;
  321.         WORD CallPort = H323EndPoint::DefaultTcpPort;
  322.         fullAddress=_dest;
  323.         if ((fullAddress.Find(':') == P_MAX_INDEX))  fullAddress += psprintf(":%i", CallPort);
  324.         cout << "Initiating test to "" << fullAddress << '"' << endl;
  325.         if (!MakeCall(fullAddress, currentCallToken)) {
  326.                 cout << "Error making call to "" << fullAddress << '"' << endl;
  327.                 return FALSE;
  328.         }
  329.         StateFlag=CallInit;
  330.         return TRUE;
  331. }
  332. // Caller - Novos Metodos - Cesar
  333. BOOL C_MyH323EndPoint::OnIncomingCall(H323Connection & _conn,
  334.                                     const H323SignalPDU & setupPDU,
  335.                                     H323SignalPDU &)
  336. {
  337.   C_MyH323Connection & conn = (C_MyH323Connection &)_conn;
  338.   // see if incoming call is to a getway address
  339.   PString number;
  340.   if (setupPDU.GetDestinationE164(number)) 
  341.     conn.SetE164Number(number);
  342.   return TRUE;
  343. }
  344. H323Connection * C_MyH323EndPoint::CreateConnection(unsigned callReference)
  345. {
  346.   return new C_MyH323Connection(*this, callReference);
  347. }
  348. BOOL C_MyH323EndPoint::Initialise(PConfigArgs & args)
  349. {
  350. // cout<<"Inside CallerMain MyEndpoint Initialisen";
  351.   // format for record files, raw or wav
  352.   if (args.HasOption("recordraw")) 
  353.     SetRecordWav(FALSE);
  354.   else
  355.     SetRecordWav(TRUE);
  356.   // get G723.1 OGM
  357.   if (args.HasOption("g7231message"))
  358.     g7231Ogm = args.GetOptionString("g7231message");
  359.   else if (args.HasOption('m'))  {
  360.     if (PFile::Exists(args.GetOptionString('m') + "_g7231" + WAVExt)) {
  361.       g7231Ogm = args.GetOptionString('m') + "_g7231" + WAVExt;
  362.   cout<<"Message file is 0: "<<g7231Ogm<<"n";
  363.     }
  364.     else if (PFile::Exists(args.GetOptionString('m') + PCMExt)) {
  365.       g7231Ogm = args.GetOptionString('m') + G7231Ext;
  366.   cout<<"Message file is 1: "<<g7231Ogm<<"n";
  367.     }
  368.   }
  369.   if (!g7231Ogm.IsEmpty()) {
  370.     // check if the file exists. (do not check if filename contains %s)
  371.     if ((g7231Ogm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(g7231Ogm)) {
  372.       cout << "warning: cannot open G723.1 OGM file "" << g7231Ogm << """ << endl;
  373.       g7231Ogm = "";
  374.     } 
  375.   }
  376.   if (g7231Ogm.IsEmpty()) {
  377. //    cout << "No G.723.1 outgoing message setn";
  378.   }
  379.   else {
  380. //    cout << "Using "" << g7231Ogm << "" as G.723.1 outgoing messagen";
  381.   }
  382.   // Get the OGM message for the 'PCM' codecs
  383.   // Check if the file specified exists. If it does, use it.
  384.   // If it does not exist, try with .wav and .sw extensions.
  385.   if (args.HasOption("pcmmessage")) {
  386.     pcmOgm = args.GetOptionString("pcmmessage");
  387.   }
  388.   else if (args.HasOption('m')) {
  389.       if (PFile::Exists(args.GetOptionString('m'))) {
  390.         pcmOgm = args.GetOptionString('m');
  391.       }
  392.       else if (PFile::Exists(args.GetOptionString('m') + WAVExt)) {
  393.         pcmOgm = args.GetOptionString('m') + WAVExt;
  394.       }
  395.       else if (PFile::Exists(args.GetOptionString('m') + PCMExt)) {
  396.         pcmOgm = args.GetOptionString('m') + PCMExt;
  397.       }
  398.   }
  399.   // By default, use the pcmOgm for all the PCM codecs, but allow the user
  400.   // to override them.
  401.   gsmOgm   = pcmOgm;
  402.   g711Ogm  = pcmOgm;
  403.   lpc10Ogm = pcmOgm;
  404.   speexOgm = pcmOgm;
  405.   // We can set the filename for specific codecs.
  406.   if (args.HasOption("gsmmessage")) 
  407.     gsmOgm = args.GetOptionString("gsmmessage");
  408.   if (args.HasOption("g711message")) 
  409.     g711Ogm = args.GetOptionString("g711message");
  410.   if (args.HasOption("lpc10message")) 
  411.     lpc10Ogm = args.GetOptionString("lpc10message");
  412.   if (args.HasOption("speexmessage")) 
  413.     speexOgm = args.GetOptionString("speexmessage");
  414.   // Check GSM OGM message
  415.   if (!gsmOgm.IsEmpty()) {
  416.     if ((gsmOgm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(gsmOgm)) {
  417.       cout << "warning: cannot open GSM OGM file "" << gsmOgm << """ << endl;
  418.       gsmOgm = "";
  419.     }
  420.   } 
  421.   if (gsmOgm.IsEmpty()) {
  422. //    cout << "No GSM outgoing message setn";
  423.   }
  424.   else {
  425. //    cout << "Using "" << gsmOgm << "" as GSM outgoing messagen";
  426.   }
  427.   // Check G.711 OGM message 
  428.   if (!g711Ogm.IsEmpty()) {
  429.     if ((g711Ogm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(g711Ogm)) {
  430.       cout << "warning: cannot open G711 OGM file "" << g711Ogm << """ << endl;
  431.       g711Ogm = "";
  432.     }
  433.   } 
  434.   if (g711Ogm.IsEmpty()) {
  435. //    cout << "No G711 outgoing message setn";
  436.   }
  437.   else {
  438. //    cout << "Using "" << g711Ogm << "" as G.711 outgoing messagen";
  439.   }
  440.   // Check LPC10 OGM message 
  441.   if (!lpc10Ogm.IsEmpty()) {
  442.     if ((lpc10Ogm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(lpc10Ogm)) {
  443.       cout << "warning: cannot open LPC10 OGM file "" << lpc10Ogm << """ << endl;
  444.       lpc10Ogm = "";
  445.     }
  446.   } 
  447.   if (lpc10Ogm.IsEmpty()) {
  448. //    cout << "No LPC10 outgoing message setn";
  449.   }
  450.   else {
  451. //    cout << "Using "" << lpc10Ogm << "" as LPC10 outgoing messagen";
  452.   }
  453.   // Check Speex OGM message 
  454.   if (!speexOgm.IsEmpty()) {
  455.     // check if the file exists. (do not check if filename contains %s)
  456.     if ((speexOgm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(speexOgm)) {
  457.       cout << "warning: cannot open Speex OGM file "" << speexOgm << """ << endl;
  458.       speexOgm = "";
  459.     }
  460.   } 
  461.   if (speexOgm.IsEmpty()) {
  462. //    cout << "No Speex outgoing message setn";
  463.   }
  464.   else {
  465. //    cout << "Using "" << speexOgm << "" as Speex outgoing messagen";
  466.   }
  467.   if (g7231Ogm.IsEmpty() && gsmOgm.IsEmpty() && g711Ogm.IsEmpty()
  468.                          && lpc10Ogm.IsEmpty() 
  469.  && speexOgm.IsEmpty()
  470.  ) {
  471.     cerr << "Must specify at least one outgoing message" << endl;
  472.     return FALSE;
  473.   }
  474.  /* if (!g7231Ogm.IsEmpty())
  475.     SetCapability(0, 0, new G7231_File_Capability);
  476.   if (!gsmOgm.IsEmpty())
  477.     SetCapability(0, 0, new H323_GSM0610Capability);
  478.   if (!gsmOgm.IsEmpty())
  479.     SetCapability(0, 0, new MicrosoftGSMAudioCapability);
  480.   */
  481.   if (!g711Ogm.IsEmpty())
  482.     SetCapability(0, 0, new H323_G711Capability(H323_G711Capability::muLaw, H323_G711Capability::At64k));
  483.   if (!g711Ogm.IsEmpty())
  484.     SetCapability(0, 0, new H323_G711Capability(H323_G711Capability::ALaw, H323_G711Capability::At64k));
  485.   /* if (!lpc10Ogm.IsEmpty())
  486.     SetCapability(0, 0, new H323_LPC10Capability(*this));
  487.   if (!speexOgm.IsEmpty())
  488.     SetCapability(0, 0, new SpeexNarrow2AudioCapability());
  489.     SetCapability(0, 0, new SpeexNarrow3AudioCapability());
  490.     SetCapability(0, 0, new SpeexNarrow4AudioCapability());
  491.     SetCapability(0, 0, new SpeexNarrow5AudioCapability());
  492.     SetCapability(0, 0, new SpeexNarrow6AudioCapability());
  493.   */
  494.   capabilities.Remove(args.GetOptionString('D').Lines());
  495.   capabilities.Reorder(args.GetOptionString('P').Lines());
  496. //  cout << "Codecs (in preference order):n" << setprecision(2) << capabilities << endl;
  497.   return TRUE;
  498. }
  499. ///////////////////////////////////////////////////////////////
  500. C_PCM_RecordFile::C_PCM_RecordFile(C_MyH323Connection & _conn, const PFilePath & _fn, unsigned _callLimit)
  501.   : conn(_conn), fn(_fn), callLimit(_callLimit)
  502. {
  503.   recordStarted = FALSE;
  504.   timeLimitExceeded = FALSE;
  505.   closed        = FALSE;
  506.   dataWritten   = FALSE;
  507.   // If the file name ends in .wav then open the output as a WAV file.
  508.   // Otherwise open it as a raw file.
  509.   if ((_fn.Right(4)).ToLower() == ".wav")
  510.     fileclass = new PWAVFile(_fn, PFile::WriteOnly,
  511.      PFile::ModeDefault,PWAVFile::PCM_WavFile);
  512.   else
  513.     fileclass = new PFile(_fn, PFile::WriteOnly);
  514. }
  515. void C_PCM_RecordFile::StartRecording()
  516. {
  517.   PWaitAndSignal mutex(pcmrecordMutex);
  518.   if (recordStarted)
  519.     return;
  520.   PTRACE(1, "Starting recording to " << fn);
  521.   PTime now;
  522.   recordStarted = TRUE;
  523.   finishTime = now + (callLimit * 1000);
  524. }
  525. BOOL C_PCM_RecordFile::Close()
  526. {
  527.   PWaitAndSignal mutex(pcmrecordMutex);
  528.   closed = TRUE;
  529.   return fileclass->Close();
  530. }
  531. BOOL C_PCM_RecordFile::Write(const void * buf, PINDEX len)
  532. {
  533.   // Wait for the mutex, and Signal it at the end of this function
  534.   PWaitAndSignal mutex(pcmrecordMutex);
  535.   // If the record file has been closed, or if the time limit has
  536.   // been exceeded, then return immediatly.
  537.   if (closed || timeLimitExceeded)
  538.     return FALSE;
  539.   if (!recordStarted) {
  540.     DelayFrame(len);
  541.     return TRUE;
  542.   }
  543.   PTime now;
  544.   if ((callLimit != 0) && (now >= finishTime)) {
  545.     PTRACE(1, "Terminating call due to timeout");
  546.     conn.ClearCall();
  547.     timeLimitExceeded = TRUE;
  548.     return TRUE;
  549.   }
  550.   DelayFrame(len);
  551.   dataWritten = TRUE;
  552.   return WriteFrame(buf, len);
  553. }
  554. BOOL C_PCM_RecordFile::WriteFrame(const void * buf, PINDEX len)
  555. {
  556.   //cerr << "Writing PCM " << len << endl;
  557.   return  fileclass->Write(buf, len);
  558. }
  559. void C_PCM_RecordFile::DelayFrame(PINDEX len)
  560. {
  561.   delay.Delay(len/16);
  562. }
  563. C_PCM_RecordFile::~C_PCM_RecordFile()
  564. {
  565.   PWaitAndSignal mutex(pcmrecordMutex);
  566.   if (!dataWritten) {
  567.     PTRACE(1, "Deleting " << fn << " as no data recorded");
  568.     fileclass->Remove(fn);
  569.   }
  570.   delete fileclass;
  571. }
  572. ///////////////////////////////////////////////////////////////
  573. // Override some of the PCM_RecordFile functions to write
  574. // G723.1 data instead of PCM data.
  575. C_G7231_RecordFile::C_G7231_RecordFile(C_MyH323Connection & _conn, const PFilePath & _fn, unsigned _callLimit)
  576.   : C_PCM_RecordFile(_conn, _fn, _callLimit)
  577. {
  578.   // If the record file is a .wav file, we need to close the file
  579.   // that PCM_RecordFile will have opened, and reopen it as a G.723.1 Wav file.
  580.   if ((_fn.Right(4)).ToLower() == ".wav") {
  581.     fileclass->Remove(_fn);
  582.     delete fileclass;
  583.     fileclass = new PWAVFile(_fn, PFile::WriteOnly,
  584.      PFile::ModeDefault,PWAVFile::G7231_WavFile);
  585.   }
  586. }
  587. BOOL C_G7231_RecordFile::WriteFrame(const void * buf, PINDEX /*len*/)
  588. {
  589.   int frameLen = G7231_File_Codec::GetFrameLen(*(BYTE *)buf);
  590. //  cerr << "Writing G7231 " << frameLen << endl;
  591.   return fileclass->Write(buf, frameLen);
  592. }
  593. void C_G7231_RecordFile::DelayFrame(PINDEX /*len*/)
  594. {
  595.   // Ignore the len parameter as that is the compressed size.
  596.   // We must delay by the actual sample time.
  597.   delay.Delay((G7231_SAMPLES_PER_BLOCK*2)/16);
  598. }
  599. ///////////////////////////////////////////////////////////////
  600. static BOOL MatchString(const PString & str1, const PString str2)
  601. {
  602.   if (str1.GetLength() != str2.GetLength())
  603.     return FALSE;
  604.   PINDEX len = str1.GetLength();
  605.   PINDEX i;
  606.   for (i = 0; i < len; i++) 
  607.     if ((str1[i] != '?') && (str2[i] != '?') && (str1[i] != str2[i]))
  608.       return FALSE;
  609.   return TRUE;
  610. }
  611. static PINDEX FindMatch(const PStringList & list, const PString & key)
  612. {
  613.   PINDEX maxKeyLen = 0;
  614.   PINDEX i;
  615.   PINDEX keyLen = key.GetLength();
  616.   PINDEX listLen = list.GetSize();
  617.   for (i = 0; i < listLen; i++)
  618.     maxKeyLen = PMAX(maxKeyLen, list[i].GetLength());
  619.   if (keyLen == 0 || maxKeyLen == 0)
  620.     return P_MAX_INDEX;
  621.   if (keyLen > maxKeyLen)
  622.     return P_MAX_INDEX;
  623.   PINDEX len = 1;
  624.   while (len <= keyLen) {
  625.     PString subStr = key.Left(len);
  626.     PINDEX matches = 0;
  627.     PINDEX lastMatch = P_MAX_INDEX;
  628.     PINDEX i;
  629.     // look for a match to the substring
  630.     for (i = 0; i < list.GetSize(); i++) {
  631.       if ((list[i].GetLength() >= keyLen) && MatchString(list[i].Left(len), subStr)) {
  632.         matches++;
  633.         lastMatch = i;
  634.       }
  635.     }
  636.     // if we got ONE match, we have a winner
  637.     if (matches == 1)
  638.       return lastMatch+1;
  639.     // if we have no matches, then there is no point continuing
  640.     if (matches == 0)
  641.       return P_MAX_INDEX;
  642.     // if we have more than one match, try the next char
  643.     len++;
  644.   }
  645.   // too many matches
  646.   return 0;
  647. }
  648. C_MyH323Connection::C_MyH323Connection(C_MyH323EndPoint & _ep, unsigned callReference)
  649.   : H323Connection(_ep, callReference), ep(_ep)
  650. {
  651.   basename = psprintf("%04i%02i%02i_%02i%02i%02i", callStartTime.GetYear(), callStartTime.GetMonth(),  callStartTime.GetDay(),
  652.                                                    callStartTime.GetHour(), callStartTime.GetMinute(), callStartTime.GetSecond());
  653.   recordFile = NULL;
  654.   ogmChannel = NULL;
  655.   receiveCodecName = transmitCodecName = "none";
  656. // SetMaxAudioDelayJitter(150);
  657.   cout << "Opening connection" << endl;
  658.   currentMenu = 0;
  659.   digits = "";
  660.   PConfig config;
  661.   PStringList sections = config.GetSections();
  662.   PINDEX i;
  663.   for (i = 0; i < sections.GetSize(); i++) {
  664.     if (sections[i].Find(MENU_PREFIX) == 0) 
  665.       menuNames.AppendString(sections[i]);
  666.   }
  667. }
  668. C_MyH323Connection::~C_MyH323Connection()
  669. {
  670.   cout << "Closing connection" << endl;
  671.   PTime now;
  672.   PTimeInterval interval = now - recordStartTime;
  673.   PString addr = GetControlChannel().GetRemoteAddress();
  674.   PString codecStr = receiveCodecName + "/" + transmitCodecName;
  675.   unsigned duration = (unsigned)((interval.GetMilliSeconds()+999)/1000);
  676.   LogCall(recordFn, addr, GetRemotePartyName(), duration, codecStr, product);
  677.   if ((recordFile!= NULL) && (recordFile->WasRecordStarted()) && !ep.GetRunCmd().IsEmpty()) {
  678.     PString cmdStr = ep.GetRunCmd() &
  679.                      recordFn &
  680.                      "'" + addr + "'" &
  681.                      """ + GetRemotePartyName() + """ &
  682.                      PString(PString::Unsigned, duration) &
  683.                      """ + codecStr + """ &
  684.                      """ + product + """;
  685.     PTRACE(1, "Executing : " << cmdStr);
  686.     system((const char *)cmdStr);
  687.   } else {
  688.     PTRACE(1, "No action to perform at end of record");
  689.   }
  690.   if (ogmChannel != NULL)
  691.     delete ogmChannel;
  692.   if (recordFile != NULL)
  693.     delete recordFile;
  694.   if (ep.GetDeleteAfterRecord()) {
  695.     PTRACE(1, "Removing " << recordFn << " as requested by option");
  696.     PFile::Remove(recordFn);
  697.   }
  698. }
  699. H323Connection::AnswerCallResponse
  700.      C_MyH323Connection::OnAnswerCall(const PString & caller,
  701.                                     const H323SignalPDU & setupPDU,
  702.                                     H323SignalPDU & /*connectPDU*/)
  703. {
  704.   product = "Unknown";
  705.   const H225_Setup_UUIE & setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
  706.   const H225_EndpointType & epInfo = setup.m_sourceInfo;
  707.   if (epInfo.HasOptionalField(H225_EndpointType::e_vendor)) {
  708.     const H225_VendorIdentifier & vendorInfo = epInfo.m_vendor;
  709.     if (vendorInfo.HasOptionalField(H225_VendorIdentifier::e_productId))
  710.       product = vendorInfo.m_productId.AsString();
  711.     if (vendorInfo.HasOptionalField(H225_VendorIdentifier::e_versionId))
  712.       product = product + "/" + vendorInfo.m_versionId.AsString();
  713.   }
  714.   
  715.   cout << "Accepting call from " << caller << " using " << product << endl;
  716.   return AnswerCallNow;
  717. }
  718. BOOL C_MyH323Connection::OpenAudioChannel(BOOL isEncoding, 
  719.                                         unsigned /* bufferSize */, 
  720.                                         H323AudioCodec & codec)
  721. {
  722.   codec.SetSilenceDetectionMode(H323AudioCodec::NoSilenceDetection);
  723.   PStringStream codecName;
  724.   codecName << codec;
  725.   PString ogm;
  726.   BOOL isPCM = FALSE;
  727.   if (codec.IsDescendant(G7231_File_Codec::Class())) {
  728.     ogm   = ep.GetG7231OGM();
  729.     isPCM = FALSE;
  730.   } else if (codec.IsDescendant(H323_GSM0610Codec::Class())) {
  731.     ogm   = ep.GetGSMOGM();
  732.     isPCM = TRUE;
  733.   } else if (codec.IsDescendant(MicrosoftGSMCodec::Class())) {
  734.     ogm   = ep.GetGSMOGM();
  735.     isPCM = TRUE;
  736.   } else if (codec.IsDescendant(H323_muLawCodec::Class())) {
  737.     ogm   = ep.GetG711OGM();
  738.     isPCM = TRUE;
  739.   } else if (codec.IsDescendant(H323_ALawCodec::Class())) {
  740.     ogm   = ep.GetG711OGM();
  741.     isPCM = TRUE;
  742.   } else if (codec.IsDescendant(H323_LPC10Codec::Class())) {
  743.     ogm   = ep.GetLPC10OGM();
  744.     isPCM = TRUE;
  745.   } else if (codec.IsDescendant(SpeexCodec::Class())) {
  746.     ogm   = ep.GetSPEEXOGM();
  747.     isPCM = TRUE;
  748.   } else {
  749.     cerr << "Unknown codec "" << codecName << endl;
  750.     return FALSE;
  751.   }
  752.   PWaitAndSignal mutex(connMutex);
  753.   if ((recordFile == NULL) && (isEncoding == FALSE)) {
  754.     if (isPCM) {
  755.       if (ep.GetRecordWav() == TRUE)
  756.       recordFn = ep.GetDirectory() + (basename + ".wav");
  757.       else
  758.       recordFn = ep.GetDirectory() + (basename + ".sw");
  759.       recordFile = new C_PCM_RecordFile  (*this, recordFn, ep.GetCallLimit());
  760.     } else {
  761.       if (ep.GetRecordWav() == TRUE)
  762.       recordFn = ep.GetDirectory() + (basename + ".wav");
  763.       else
  764.       recordFn = ep.GetDirectory() + (basename + ".g723");
  765.       recordFile = new C_G7231_RecordFile(*this, recordFn, ep.GetCallLimit());
  766.     }
  767.   }
  768.   if ((ogmChannel == NULL) && (isEncoding == TRUE)) {
  769.     if (isPCM)
  770.       ogmChannel = new C_PCM_OGMChannel(*this);
  771.     else
  772.       ogmChannel = new C_G7231_OGMChannel(*this);
  773.   }
  774.   if (isEncoding) {
  775.     if (ep.GetHangupAfterPlay())
  776.       ogmChannel->SetPlayOnce();
  777.     if (ogm.Find("%s"))
  778.       ogm.Replace("%s", e164Number);
  779.     transmitCodecName = codecName;
  780.     if (!StartMenu(0)) {
  781.       if (!PFile::Exists(ogm))
  782.         cerr << "error: cannot find OGM "" << ogm << """ << endl;
  783.       else
  784.         ogmChannel->QueueFile(ogm);
  785.       if (!ep.GetNoRecordG7231())
  786.         ogmChannel->SetRecordTrigger();
  787.     }
  788.     codec.AttachChannel(ogmChannel, FALSE);
  789.   } else {
  790.     receiveCodecName = codecName;
  791.     codec.AttachChannel(recordFile, FALSE);
  792.   }
  793.   return TRUE;
  794. }
  795. BOOL C_MyH323Connection::OnStartLogicalChannel(H323Channel & channel)
  796. {
  797.   if (!H323Connection::OnStartLogicalChannel(channel))
  798.     return FALSE;
  799.   cout << "Started logical channel: ";
  800.   switch (channel.GetDirection()) {
  801.     case H323Channel::IsTransmitter :
  802.       cout << "sending ";
  803.       break;
  804.     case H323Channel::IsReceiver :
  805.       cout << "receiving ";
  806.       break;
  807.     default :
  808.       break;
  809.   }
  810.   cout << channel.GetCapability() << endl;
  811.   return TRUE;
  812. }
  813. void C_MyH323Connection::StartRecording()
  814. {
  815.   recordFile->StartRecording();
  816. }
  817. void C_MyH323Connection::OnUserInputString(const PString & value)
  818. {
  819.   PINDEX i;
  820.   for (i = 0; i < value.GetLength(); i++) {
  821.     OnUserInputChar(value[i]);
  822.   }
  823. }
  824. BOOL C_MyH323Connection::StartMenu(int menuNumber)
  825. {
  826.   digits = "";
  827.   currentMenu = menuNumber;
  828.   PString menuName = psprintf("%s%i", MENU_PREFIX, menuNumber);
  829.   if (menuNames.GetStringsIndex(menuName) == P_MAX_INDEX) 
  830.     return FALSE;
  831.   PTRACE(1, "Starting menu " << menuNumber);
  832.   PConfig menu(menuName);
  833.   PString startCmd = menu.GetString("start");
  834.   if (!startCmd.IsEmpty())
  835.     ProcessMenuCmd(startCmd);
  836.   return TRUE;
  837. }
  838. BOOL C_MyH323Connection::ProcessMenuCmd(const PString & cmdStr)
  839. {
  840.   PTRACE(1, "Processing menu cmd " << cmdStr);
  841.   PStringArray tokens = cmdStr.Tokenise(" ", FALSE);
  842.   int len = tokens.GetSize();
  843.   if (len == 0)
  844.     return TRUE;
  845.   PString cmd = tokens[0];
  846.   if ((len >= 2) && (cmd *= "play")) {
  847.     ogmChannel->QueueFile(tokens[1]);
  848.     if (len > 2) {
  849.       cmd = "menu";
  850.       tokens[1] = tokens[2];
  851.     }
  852.   }
  853.   if ((len >= 2) && (cmd *= "menu")) {
  854.     int newMenu = tokens[1].AsInteger();
  855.     if (newMenu != currentMenu)
  856.       StartMenu(newMenu);
  857.   }
  858.   else if (cmd *= "hangup")
  859.     ogmChannel->SetHangupTrigger();
  860.   else if (cmd *= "record")
  861.     ogmChannel->SetRecordTrigger();
  862.   return TRUE;
  863. }
  864. void C_MyH323Connection::OnUserInputChar(char ch)
  865. {
  866.   if (ch == '#') 
  867.     digits += '$';
  868.   else 
  869.     digits += ch;
  870.   PTRACE(1, "Processing digit string " << digits);
  871.   ogmChannel->FlushQueue();
  872.   PString menuName = psprintf("%s%i", MENU_PREFIX, currentMenu);
  873.   if (menuNames.GetStringsIndex(menuName) == P_MAX_INDEX) {
  874.     PTRACE(1, "Cannot find menu " << menuName);
  875.     StartMenu(0);
  876.     return;
  877.   }
  878.   PConfig menu(menuName);
  879.   PStringList keys = menu.GetKeys();
  880.   PINDEX keyMatch = FindMatch(keys, digits);
  881.   // if key is still ambiguous, then keep collecting
  882.   if (keyMatch == 0)
  883.     return;
  884.   PString cmd;
  885.   if (keyMatch != P_MAX_INDEX) {
  886.     PString key = keys[keyMatch-1];
  887.     PTRACE(1, "Executing cmd for key " << key);
  888.     cmd = menu.GetString(key);
  889.   } else {
  890.     PTRACE(1, "Cannot match cmd " << digits << " in menu " << menuName);
  891.     cmd = menu.GetString("error", "menu 0");
  892.   } 
  893.   if (!cmd.IsEmpty()) {
  894.     ProcessMenuCmd(cmd);
  895.     digits = "";
  896.   }
  897. }
  898. ///////////////////////////////////////////////////////////////
  899. /*BOOL CheckWAVFileValid(PWAVFile *chan, int type) {
  900.   // Check the wave file header
  901.   if (!chan->IsValid()) {
  902.     PTRACE(1, chan->GetName() << " wav file header invalid");
  903.     return FALSE;
  904.   }
  905.   // Check the wave file format
  906.   if ( (type == CHECK_PCM) && (chan->GetFormat() != 0x01) ){
  907.     PTRACE(1, chan->GetName() << " is not a PCM format wav file");
  908.     PTRACE(1, "It is format " << chan->GetFormat() );
  909.     return FALSE;
  910.   }
  911.   if ( (type == CHECK_G7231) && 
  912.        ((chan->GetFormat() != 0x42) && (chan->GetFormat() != 0x111)) ){
  913.     PTRACE(1, chan->GetName() << " is not a G.723.1 format wav file");
  914.     PTRACE(1, "It is format " << chan->GetFormat() );
  915.     return FALSE;
  916.   }
  917.   // Check the sample rate for PCM wave files
  918.   if ( (type == CHECK_PCM) &&
  919.        ( (chan->GetSampleRate() != 8000)
  920.        ||(chan->GetChannels() != 1)
  921.        ||(chan->GetSampleSize() != 16) )
  922.      ) {
  923.     PTRACE(1, chan->GetName() << " is not a 16 Bit, Mono, 8000 Hz (8Khz) PCM wav file");
  924.     PTRACE(1, "It is " << chan->GetSampleSize() << " bits, "
  925.                        << (chan->GetChannels()==1 ? "mono " : "stereo ")
  926.                        << chan->GetSampleRate() << " Hz");
  927.     return FALSE;
  928.   }
  929.   return TRUE;
  930. }*/
  931. ///////////////////////////////////////////////////////////////
  932. C_PCM_OGMChannel::C_PCM_OGMChannel(C_MyH323Connection & _conn)
  933.   : conn(_conn)
  934. {
  935.   silentCount = 20;         // wait 20 frames before playing the OGM
  936.   recordTrigger = FALSE;
  937.   hangupTrigger = FALSE;
  938.   closed        = FALSE;
  939.   playOnce      = FALSE;
  940.   frameLen = frameOffs = 0;
  941. }
  942. void C_PCM_OGMChannel::PlayFile(PFile * chan)
  943.   PWaitAndSignal mutex(chanMutex);
  944. //  if (IsOpen())
  945. //    Close();
  946.   if (!chan->Open(PFile::ReadOnly)) {
  947.     PTRACE(1, "Cannot open file "" << chan->GetName() << """);
  948.     return;
  949.   }
  950.   PTRACE(1, "Playing file "" << chan->GetName() << """);
  951.   totalData = 0;
  952.   SetReadChannel(chan, TRUE);
  953. }
  954. BOOL C_PCM_OGMChannel::IsWAVFileValid(PWAVFile *chan) {
  955.   // Check that this is a PCM wave file
  956.   return CheckWAVFileValid(chan, CHECK_PCM);
  957. }
  958. BOOL C_PCM_OGMChannel::Read(void * buffer, PINDEX amount)
  959. {
  960.   PWaitAndSignal mutex(chanMutex);
  961.   // if the channel is closed, then return error
  962.   if (closed)
  963.     return FALSE;
  964.   // Create the frame buffer using the amount of bytes the codec wants to
  965.   // read. Different codecs use different read sizes.
  966.   frameBuffer.SetMinSize(1024);//amount);
  967.   // assume we are returning silence
  968.   BOOL doSilence = TRUE;
  969.   BOOL frameBoundary = FALSE;
  970.   // if still outputting a frame from last time, then keep doing it
  971.   if (frameOffs < frameLen) {
  972.     frameBoundary = AdjustFrame(buffer, amount);
  973.     doSilence = FALSE;
  974.   } else {
  975.     // if we are returning silence frames, then 
  976.     if (silentCount > 0) 
  977.       silentCount--;
  978.     // if a channel is already open, don't do silence
  979.     else if (GetBaseReadChannel() != NULL)
  980.       doSilence = FALSE;
  981.     // If not in silence and no existing channel, open a new file.
  982.     else {
  983.       PString * str = playQueue.Dequeue();
  984.       if (str != NULL) {
  985.         // check the file extension and open a .wav or a raw (.sw or .g723) file
  986.         if (((*str).Right(4)).ToLower() == ".wav") {
  987.           PWAVFile *chan;
  988.           chan = new PWAVFile(*str, PFile::ReadOnly);
  989.           if (!chan->IsOpen()) {
  990.             PTRACE(1, "Cannot open file "" << chan->GetName() << """);
  991.             delete chan;
  992.           } else {
  993.           if (!IsWAVFileValid(chan) ){
  994.               PTRACE(1, chan->GetName() << " is not a valid wav file");
  995.               delete chan;
  996.               cerr << "wave file is invalid" << endl;
  997.             } else {
  998.               PTRACE(1, "Playing file "" << chan->GetName() << """);
  999.               totalData = 0;
  1000.               SetReadChannel(chan, TRUE);
  1001.               doSilence = FALSE;
  1002.             }
  1003.   }
  1004.         } else { // raw file (eg .sw)
  1005.           PFile *chan;
  1006.           chan = new PFile(*str);
  1007.           if (!chan->Open(PFile::ReadOnly)) {
  1008.             PTRACE(1, "Cannot open file "" << chan->GetName() << """);
  1009.             delete chan;
  1010.           } else {
  1011.             PTRACE(1, "Playing file "" << chan->GetName() << """);
  1012.             totalData = 0;
  1013.             SetReadChannel(chan, TRUE);
  1014.             doSilence = FALSE;
  1015.           }
  1016.         }
  1017.         delete str;
  1018.       }
  1019.     }
  1020.   
  1021.     // if not doing silence, try and read from the file
  1022.     if (!doSilence) {
  1023.   
  1024.       if (ReadFrame(amount)) {
  1025.         frameBoundary = AdjustFrame(buffer, amount);
  1026.         totalData += amount;
  1027.   
  1028.       } else {
  1029.         PTRACE(1, "Finished playing " << totalData << " bytes");
  1030.         //closed = TRUE;
  1031.   
  1032.         PIndirectChannel::Close();
  1033.         silentCount = 5;   // always do 5 frames of silence after every file
  1034.   
  1035.         // hangup if required
  1036.         if (hangupTrigger || playOnce) 
  1037.           conn.ClearCall();
  1038.   
  1039.         // trigger record if required
  1040.         else if (recordTrigger) {
  1041.           if ((playQueue.GetSize() == 0) && (GetBaseReadChannel() == NULL))
  1042.             conn.StartRecording();
  1043.       }
  1044.    
  1045.         // no silence
  1046.         doSilence = TRUE;
  1047.       }
  1048.     }
  1049.   }
  1050.   
  1051.   // start silence frame if required
  1052.   if (doSilence) {
  1053.     CreateSilenceFrame(amount);
  1054.     frameBoundary = AdjustFrame(buffer, amount);
  1055.   }
  1056.   // delay to synchronise to frame boundary
  1057.   if (frameBoundary)
  1058.     Synchronise(amount);
  1059.   return TRUE;
  1060. }
  1061. BOOL C_PCM_OGMChannel::Close()
  1062. {
  1063.   PWaitAndSignal mutex(chanMutex);
  1064.   closed = TRUE;
  1065.   PIndirectChannel::Close();
  1066.   return TRUE;
  1067. }
  1068. void C_PCM_OGMChannel::SetRecordTrigger()
  1069. {
  1070.   PWaitAndSignal mutex(chanMutex);
  1071.   recordTrigger = TRUE;
  1072.   if ((playQueue.GetSize() == 0) && (GetBaseReadChannel() == NULL))
  1073.     conn.StartRecording();
  1074. }
  1075. void C_PCM_OGMChannel::SetHangupTrigger()
  1076. {
  1077.   PWaitAndSignal mutex(chanMutex);
  1078.   hangupTrigger = TRUE;
  1079.   if (GetBaseReadChannel() == NULL)
  1080.     conn.ClearCall();
  1081. }
  1082. void C_PCM_OGMChannel::QueueFile(const PString & fn)
  1083. {
  1084.   PWaitAndSignal mutex(chanMutex);
  1085.   PTRACE(1, "Enqueueing file " << fn << " for playing");
  1086.   playQueue.Enqueue(new PString(fn));
  1087. }
  1088. void C_PCM_OGMChannel::FlushQueue()
  1089. {
  1090.   PWaitAndSignal mutex(chanMutex);
  1091.   if (GetBaseReadChannel() != NULL) {
  1092.     PIndirectChannel::Close();
  1093.     if (hangupTrigger) 
  1094.       conn.ClearCall();
  1095.     else if (recordTrigger) 
  1096.       conn.StartRecording();
  1097.   }
  1098.   PString * str;
  1099.   while ((str = playQueue.Dequeue()) != NULL)
  1100.     delete str;
  1101. }
  1102. BOOL C_PCM_OGMChannel::AdjustFrame(void * buffer, PINDEX amount)
  1103. {
  1104.   if ((frameOffs + amount) > frameLen) {
  1105.     cerr << "Reading past end of frame:offs=" << frameOffs << ",amt=" << amount << ",len=" << frameLen << endl;
  1106.     return TRUE;
  1107.   }
  1108.   //PAssert((frameOffs + amount) <= frameLen, "Reading past end of frame");
  1109.   memcpy(buffer, frameBuffer.GetPointer()+frameOffs, amount);
  1110.   frameOffs += amount;
  1111.   lastReadCount = amount;
  1112.   return frameOffs == frameLen;
  1113. }
  1114. void C_PCM_OGMChannel::Synchronise(PINDEX amount)
  1115. {
  1116.   ogm_delay.Delay(amount / 16);
  1117. }
  1118. BOOL C_PCM_OGMChannel::ReadFrame(PINDEX amount)
  1119. {
  1120.   frameOffs = 0;
  1121.   frameLen  = amount;
  1122.   BOOL result = PIndirectChannel::Read(frameBuffer.GetPointer(), frameLen);
  1123.   // if we did not read a full frame of audio, fill the end of the
  1124.   // frame with zeros.
  1125.   PINDEX count = GetLastReadCount();
  1126.   if (count < frameLen)
  1127.     memset(frameBuffer.GetPointer()+count, 0, frameLen-count);
  1128.   return result;
  1129. }
  1130. void C_PCM_OGMChannel::CreateSilenceFrame(PINDEX amount)
  1131. {
  1132.   frameOffs = 0;
  1133.   frameLen  = amount;
  1134.   memset(frameBuffer.GetPointer(), 0, frameLen);
  1135. }
  1136. ///////////////////////////////////////////////////////////////
  1137. C_G7231_OGMChannel::C_G7231_OGMChannel(C_MyH323Connection & conn)
  1138.   : C_PCM_OGMChannel(conn)
  1139. {
  1140. }
  1141. void C_G7231_OGMChannel::Synchronise(PINDEX /*amount*/)
  1142. {
  1143.   ogm_delay.Delay(30);
  1144. }
  1145. BOOL C_G7231_OGMChannel::ReadFrame(PINDEX /*amount*/)
  1146. {
  1147.   if (!PIndirectChannel::Read(frameBuffer.GetPointer(), 1))
  1148.     return FALSE;
  1149.   frameOffs = 0;
  1150.   frameLen = G7231_File_Codec::GetFrameLen(frameBuffer[0]);
  1151.   return PIndirectChannel::Read(frameBuffer.GetPointer()+1, frameLen-1);
  1152. }
  1153. void C_G7231_OGMChannel::CreateSilenceFrame(PINDEX /*amount*/)
  1154. {
  1155.   frameOffs = 0;
  1156.   frameLen  = 4;
  1157.   frameBuffer[0] = 2;
  1158.   memset(frameBuffer.GetPointer()+1, 0, 3);
  1159. }
  1160. BOOL C_G7231_OGMChannel::IsWAVFileValid(PWAVFile *chan) {
  1161.   // Check that this is a G.723.1 wave file
  1162.   return CheckWAVFileValid(chan, CHECK_G7231);
  1163. }
  1164. ///////////////////////////////////////////////////////////////