callermain.cxx
上传用户:wzkunzhan
上传日期:2022-04-23
资源大小:2618k
文件大小:41k
- /*
- * main.cxx
- *
- * Main source for for OpenAM
- *
- * A H.323 answering machine application.
- *
- * Copyright (c) 1993-2001 Equivalence Pty. Ltd.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is Portable Windows Library.
- *
- * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
- *
- * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
- * All Rights Reserved.
- *
- */
- #include <ptlib.h>
- #include <ptlib/pipechan.h>
- #include "version.h"
- #include "lpc10codec.h"
- #include "speexcodec.h"
- #include "mscodecs.h"
- #include "opalvxml.h"
- #include "callermain.h"
- //PCREATE_PROCESS(Caller);
- #define new PNEW
- #define DEFAULT_MSG_LIMIT 30
- #define DEFAULT_CALL_LOG "call_log.txt"
- #define G7231_SAMPLES_PER_BLOCK 240
- #define CHECK_PCM 1
- #define CHECK_G7231 2
- #define MENU_PREFIX "UserMenu-"
- static PMutex logMutex;
- static PTextFile logFile;
- static PFilePath logFilename = DEFAULT_CALL_LOG;
- extern PString G7231Ext;
- extern PString WAVExt;
- extern PString PCMExt;
- extern BOOL CheckWAVFileValid(PWAVFile *chan, int type);
- static void LogMessage(const PString & str)
- {
- PTime now;
- PString msg = now.AsString("hh:mm:ss dd/MM/yyyy") & str;
- logMutex.Wait();
- if (!logFile.IsOpen()) {
- logFile.Open(logFilename, PFile::ReadWrite);
- logFile.SetPosition(0, PFile::End);
- }
- logFile.WriteLine(msg);
- logFile.Close();
-
- logMutex.Signal();
- }
- static void LogCall(const PFilePath & fn,
- const PString & from,
- const PString & user,
- unsigned len,
- const PString & codec,
- const PString & product)
- {
- PString addr = from;
- LogMessage(addr & """ + user + """ & PString(PString::Unsigned, len) & codec & """ + product + """ & """ + fn + """);
- }
- ///////////////////////////////////////////////////////////////
- /*
- Caller::Caller()
- : PProcess("NCE VOIP Project", "Caller",
- MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
- {
- }
- */
- Caller::Caller()
- : PObject()
- {
- }
- Caller::~Caller()
- {
- }
- void Caller::CallerMain(PString Cargs)
- {
- // cout << GetName()
- // << " Version " << GetVersion(TRUE)
- // << " by " << GetManufacturer()
- // << " on " << GetOSClass() << ' ' << GetOSName()
- // << " (" << GetOSVersion() << '-' << GetOSHardware() << ")nn";
- // cout <<"Inside the Caller..n";
- //PConfigArgs args(GetArguments());
- PConfigArgs args(Cargs);
- args.Parse(
- "D-disable:"
- "d-directory:"
- "g-gatekeeper:" "n-no-gatekeeper."
- "-g711-ulaw." "-no-g711-ulaw."
- "-g711-alaw." "-no-g711-alaw."
- "-g711message:" "-no-g711message."
- "-g7231." "-no-g7231."
- "-g7231message:" "-no-g7231message."
- "-gsm." "-no-gsm."
- "-gsmmessage:" "-no-gsmmessage."
- "h-help."
- "H-hangup." "-no-hangup."
- "i-interface:" "-no-interface."
- "k-kill." "-no-kill."
- "l-limit:" "-no-limit."
- "-listenport:" "-no-listenport."
- "-lpc10message:" "-no-lpc10message."
- "-speexmessage:" "-no-speexmessage."
- "m-message:" "-no-message."
- "-no-recordg7231."
- #if PTRACING
- "o-output:"
- #endif
- "P-prefer:"
- "-pcm." "-no-pcm."
- "-pcmmessage:" "-no-pcmmessage."
- "-port:"
- "q-quicknet:" "-no-quicknet:"
- "r-run:" "-no-run."
- "-recordraw."
- "-require-gatekeeper." "-no-require-gatekeeper."
- "-save."
- #if PMEMORY_CHECK
- "-setallocationbreakpoint:"
- #endif
- #if PTRACING
- "t-trace."
- #endif
- "u-username:" "-no-username."
- , FALSE);
- #if PMEMORY_CHECK
- if (args.HasOption("setallocationbreakpoint"))
- PMemoryHeap::SetAllocationBreakpoint(args.GetOptionString("setallocationbreakpoint").AsInteger());
- #endif
- #if PTRACING
- PTrace::Initialise(args.GetOptionCount('t'),
- args.HasOption('o') ? (const char *)args.GetOptionString('o') : NULL);
- #endif
- if (args.HasOption('h')) {
- cout << "Usage : " << "-d"<< " [options]n"
- "Options:n"
- " -d --directory dir : Put recorded mesages into dirn"
- " -l --limit secs : Limit recorded messages to secs duration (default " << DEFAULT_MSG_LIMIT << ")n"
- " -m --pcmmessage fn : Set outgoing message for PCM derived codecs (G.711/GSM) to fnn"
- " --g7231message fn : Set outgoing message for G723.1 codec to fnn"
- " --g711message fn : Set outgoing message for G711 codec to fnn"
- " --gsmmessage fn : Set outgoing message for GSM codec to fnn"
- " --lpc10message fn : Set outgoing message for LPC10 codec to fnn"
- " --speexmessage fn : Set outgoing message for Speex codec to fnn"
- " --recordraw : Record PCM audo in raw files (.sw) instead of .wavn"
- " -r --run cmd : Run this command after each recorded messagen"
- " -k --kill : Kill recorded files after user commandn"
- " -H --hangup : hangup after playing messagen"
- " -u --username str : Set the local endpoint name to strn"
- " -i --interface ip : Bind to a specific interfacen"
- " --listenport port : Listen on a specific portn"
- " -g --gatekeeper host: Specify gatekeeper host.n"
- " -n --no-gatekeeper : Disable gatekeeper discovery.n"
- " --require-gatekeeper: Exit if gatekeeper discovery fails.n"
- " -D --disable codec : Disable the specified codec (may be used multiple times)n"
- " -P --prefer codec : Prefer the specified codec (may be used multiple times)n"
- #if PTRACING
- " -t --trace : Enable trace, use multiple times for more detailn"
- " -o --output : File for trace output, default is stderrn"
- #endif
- " --save : Save arguments in configuration filen"
- " -h --help : Display this help messagen";
- return;
- }
- args.Save("save");
- #if HAS_IXJ
- if (args.GetCount() > 0) {
- if (args[0] *= "record")
- RecordFile(args);
- else if (args[0] *= "play")
- PlayFile(args);
- else {
- //cout << "No Command -> assuming destination address." << endl;
- }
- // cerr << "unknown command "" << args[0] << """ << endl;
- // return;
- }
- #endif
- unsigned callLimit = DEFAULT_MSG_LIMIT;
- if (args.HasOption('l')) {
- callLimit = args.GetOptionString('l').AsInteger();
- if (callLimit > 3600) {
- cout << "warning: maximum call length " << callLimit << " is out of range. Using " << DEFAULT_MSG_LIMIT << " insteadn";
- callLimit = DEFAULT_MSG_LIMIT;
- } else if (callLimit == 0)
- cout << "warning: recorded message call limit disabledn";
- }
- // cout << "Recorded messages limited to " << callLimit << " secondsn";
- cout <<"Duration of the test session is expected to be approximately 3-5 minutes. nPlease Be Patient...n";
- PString runCmd;
- if (args.HasOption('r')) {
- runCmd = args.GetOptionString('r');
- cout << "Executing "" << runCmd << "" after each message" << endl;
- }
- PDirectory dir;
- if (args.HasOption('d'))
- dir = args.GetOptionString('d');
- int flags = 0;
- if (args.HasOption("no-recordg7231")) {
- cout << "Supressing recording of G723.1 messages" << endl;
- flags |= C_MyH323EndPoint::NoRecordG7231;
- }
- if (args.HasOption('k')) {
- cout << "Deleting recorded files after processing" << endl;
- if (runCmd.IsEmpty())
- cout << "WARNING: recorded files will be deleted even though no run command is present" << endl;
- flags |= C_MyH323EndPoint::DeleteAfterRecord;
- }
- if (args.HasOption('H'))
- flags |= C_MyH323EndPoint::HangupAfterPlay;
-
- // cout<<"before endpointn";
- C_MyH323EndPoint endpoint(callLimit, runCmd, dir, flags);
- // cout<<"After endpointn";
- /* PString userName = "OpenH323 Answering Machine v" + GetVersion();
- if (args.HasOption('u'))
- userName = args.GetOptionString('u');
- endpoint.SetLocalUserName(userName);*/
- if (!endpoint.Initialise(args))
- return;
- // start the H.323 listener
- /* Codigo retirado do Openam para implementacao do Caller
- H323ListenerTCP * listener;
- PIPSocket::Address interfaceAddress(INADDR_ANY);
- WORD listenPort = H323EndPoint::DefaultTcpPort;
- if (args.HasOption("listenport"))
- listenPort = (WORD)args.GetOptionString("listenport").AsInteger();
- if (args.HasOption('i'))
- interfaceAddress = PIPSocket::Address(args.GetOptionString('i'));
- listener = new H323ListenerTCP(endpoint, interfaceAddress, listenPort);
- if (!endpoint.StartListener(listener)) {
- cout << "Could not open H.323 listener port on "
- << listener->GetListenerPort() << endl;
- delete listener;
- return;
- }
- */
- if (args.HasOption('g')) {
- PString gkName = args.GetOptionString('g');
- if (endpoint.SetGatekeeper(gkName, new H323TransportUDP(endpoint)))
- cout << "Gatekeeper set: " << *endpoint.GetGatekeeper() << endl;
- else {
- cout << "Error registering with gatekeeper at "" << gkName << '"' << endl;
- return;
- }
- }
- /* else if (!args.HasOption('n')) {
- cout << "Searching for gatekeeper..." << flush;
- if (endpoint.DiscoverGatekeeper(new H323TransportUDP(endpoint)))
- cout << "nGatekeeper found: " << *endpoint.GetGatekeeper() << endl;
- else {
- cout << "nNo gatekeeper found." << endl;
- if (args.HasOption("require-gatekeeper"))
- return;
- }
- }*/
- /*
- cout << "Waiting for incoming calls for "" << endpoint.GetLocalUserName() << '"' << endl;
- for (;;)
- PThread::Current()->Sleep(5000);
- */
- if (endpoint.MakeOutgoingCall(args[0])) {
- endpoint.AwaitTermination();
- } else {
- cout << "Sorry, Exiting..." << endl;
- return;
- }
- }
- ///////////////////////////////////////////////////////////////
- C_MyH323EndPoint::C_MyH323EndPoint(unsigned _callLimit,
- const PString & _runCmd,
- const PDirectory & _dir,
- int _flags)
- : callLimit(_callLimit), runCmd(_runCmd), dir(_dir), flags(_flags)
- {
- }
- // Caller - Novos Metodos - Cesar
- BOOL C_MyH323EndPoint::OnAlerting( H323Connection & _conn, const H323SignalPDU & _SPDU, const PString & _user)
- {
- cout << " Ringing to " << _user << endl;
- return TRUE;
- }
- void C_MyH323EndPoint::OnConnectionEstablished( H323Connection & _conn , const PString & _token )
- {
- C_MyH323Connection & conn = (C_MyH323Connection &)_conn;
- RTP_Session * session = conn.GetSession(RTP_Session::DefaultAudioSessionID);
- session->SetReportTimeInterval(1000);
- StateFlag=InCall;
- }
- void C_MyH323EndPoint::OnConnectionCleared( H323Connection & _conn, const PString & _token )
- {
- StateFlag=CallClosed;
- }
- void C_MyH323EndPoint::AwaitTermination()
- {
- for (;;)
- {
- if (StateFlag!=CallClosed) PThread::Current()->Sleep(5000);
- else break;
- }
- }
- BOOL C_MyH323EndPoint::MakeOutgoingCall(const PString & _dest)
- {
- PString fullAddress;
- // WORD CallPort = H323ListenerTCP::DefaultSignalPort;
- WORD CallPort = H323EndPoint::DefaultTcpPort;
- fullAddress=_dest;
- if ((fullAddress.Find(':') == P_MAX_INDEX)) fullAddress += psprintf(":%i", CallPort);
- cout << "Initiating test to "" << fullAddress << '"' << endl;
- if (!MakeCall(fullAddress, currentCallToken)) {
- cout << "Error making call to "" << fullAddress << '"' << endl;
- return FALSE;
- }
- StateFlag=CallInit;
- return TRUE;
- }
- // Caller - Novos Metodos - Cesar
- BOOL C_MyH323EndPoint::OnIncomingCall(H323Connection & _conn,
- const H323SignalPDU & setupPDU,
- H323SignalPDU &)
- {
- C_MyH323Connection & conn = (C_MyH323Connection &)_conn;
- // see if incoming call is to a getway address
- PString number;
- if (setupPDU.GetDestinationE164(number))
- conn.SetE164Number(number);
- return TRUE;
- }
- H323Connection * C_MyH323EndPoint::CreateConnection(unsigned callReference)
- {
- return new C_MyH323Connection(*this, callReference);
- }
- BOOL C_MyH323EndPoint::Initialise(PConfigArgs & args)
- {
- // cout<<"Inside CallerMain MyEndpoint Initialisen";
- // format for record files, raw or wav
- if (args.HasOption("recordraw"))
- SetRecordWav(FALSE);
- else
- SetRecordWav(TRUE);
- // get G723.1 OGM
- if (args.HasOption("g7231message"))
- g7231Ogm = args.GetOptionString("g7231message");
- else if (args.HasOption('m')) {
- if (PFile::Exists(args.GetOptionString('m') + "_g7231" + WAVExt)) {
- g7231Ogm = args.GetOptionString('m') + "_g7231" + WAVExt;
- cout<<"Message file is 0: "<<g7231Ogm<<"n";
- }
- else if (PFile::Exists(args.GetOptionString('m') + PCMExt)) {
- g7231Ogm = args.GetOptionString('m') + G7231Ext;
- cout<<"Message file is 1: "<<g7231Ogm<<"n";
- }
- }
- if (!g7231Ogm.IsEmpty()) {
- // check if the file exists. (do not check if filename contains %s)
- if ((g7231Ogm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(g7231Ogm)) {
- cout << "warning: cannot open G723.1 OGM file "" << g7231Ogm << """ << endl;
- g7231Ogm = "";
- }
- }
- if (g7231Ogm.IsEmpty()) {
- // cout << "No G.723.1 outgoing message setn";
- }
- else {
- // cout << "Using "" << g7231Ogm << "" as G.723.1 outgoing messagen";
- }
- // Get the OGM message for the 'PCM' codecs
- // Check if the file specified exists. If it does, use it.
- // If it does not exist, try with .wav and .sw extensions.
- if (args.HasOption("pcmmessage")) {
- pcmOgm = args.GetOptionString("pcmmessage");
- }
- else if (args.HasOption('m')) {
- if (PFile::Exists(args.GetOptionString('m'))) {
- pcmOgm = args.GetOptionString('m');
- }
- else if (PFile::Exists(args.GetOptionString('m') + WAVExt)) {
- pcmOgm = args.GetOptionString('m') + WAVExt;
- }
- else if (PFile::Exists(args.GetOptionString('m') + PCMExt)) {
- pcmOgm = args.GetOptionString('m') + PCMExt;
- }
- }
- // By default, use the pcmOgm for all the PCM codecs, but allow the user
- // to override them.
- gsmOgm = pcmOgm;
- g711Ogm = pcmOgm;
- lpc10Ogm = pcmOgm;
- speexOgm = pcmOgm;
- // We can set the filename for specific codecs.
- if (args.HasOption("gsmmessage"))
- gsmOgm = args.GetOptionString("gsmmessage");
- if (args.HasOption("g711message"))
- g711Ogm = args.GetOptionString("g711message");
- if (args.HasOption("lpc10message"))
- lpc10Ogm = args.GetOptionString("lpc10message");
- if (args.HasOption("speexmessage"))
- speexOgm = args.GetOptionString("speexmessage");
- // Check GSM OGM message
- if (!gsmOgm.IsEmpty()) {
- if ((gsmOgm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(gsmOgm)) {
- cout << "warning: cannot open GSM OGM file "" << gsmOgm << """ << endl;
- gsmOgm = "";
- }
- }
- if (gsmOgm.IsEmpty()) {
- // cout << "No GSM outgoing message setn";
- }
- else {
- // cout << "Using "" << gsmOgm << "" as GSM outgoing messagen";
- }
- // Check G.711 OGM message
- if (!g711Ogm.IsEmpty()) {
- if ((g711Ogm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(g711Ogm)) {
- cout << "warning: cannot open G711 OGM file "" << g711Ogm << """ << endl;
- g711Ogm = "";
- }
- }
- if (g711Ogm.IsEmpty()) {
- // cout << "No G711 outgoing message setn";
- }
- else {
- // cout << "Using "" << g711Ogm << "" as G.711 outgoing messagen";
- }
- // Check LPC10 OGM message
- if (!lpc10Ogm.IsEmpty()) {
- if ((lpc10Ogm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(lpc10Ogm)) {
- cout << "warning: cannot open LPC10 OGM file "" << lpc10Ogm << """ << endl;
- lpc10Ogm = "";
- }
- }
- if (lpc10Ogm.IsEmpty()) {
- // cout << "No LPC10 outgoing message setn";
- }
- else {
- // cout << "Using "" << lpc10Ogm << "" as LPC10 outgoing messagen";
- }
- // Check Speex OGM message
- if (!speexOgm.IsEmpty()) {
- // check if the file exists. (do not check if filename contains %s)
- if ((speexOgm.Find("%s") == P_MAX_INDEX) && !PFile::Exists(speexOgm)) {
- cout << "warning: cannot open Speex OGM file "" << speexOgm << """ << endl;
- speexOgm = "";
- }
- }
- if (speexOgm.IsEmpty()) {
- // cout << "No Speex outgoing message setn";
- }
- else {
- // cout << "Using "" << speexOgm << "" as Speex outgoing messagen";
- }
- if (g7231Ogm.IsEmpty() && gsmOgm.IsEmpty() && g711Ogm.IsEmpty()
- && lpc10Ogm.IsEmpty()
- && speexOgm.IsEmpty()
- ) {
- cerr << "Must specify at least one outgoing message" << endl;
- return FALSE;
- }
- /* if (!g7231Ogm.IsEmpty())
- SetCapability(0, 0, new G7231_File_Capability);
- if (!gsmOgm.IsEmpty())
- SetCapability(0, 0, new H323_GSM0610Capability);
- if (!gsmOgm.IsEmpty())
- SetCapability(0, 0, new MicrosoftGSMAudioCapability);
- */
- if (!g711Ogm.IsEmpty())
- SetCapability(0, 0, new H323_G711Capability(H323_G711Capability::muLaw, H323_G711Capability::At64k));
- if (!g711Ogm.IsEmpty())
- SetCapability(0, 0, new H323_G711Capability(H323_G711Capability::ALaw, H323_G711Capability::At64k));
- /* if (!lpc10Ogm.IsEmpty())
- SetCapability(0, 0, new H323_LPC10Capability(*this));
- if (!speexOgm.IsEmpty())
- SetCapability(0, 0, new SpeexNarrow2AudioCapability());
- SetCapability(0, 0, new SpeexNarrow3AudioCapability());
- SetCapability(0, 0, new SpeexNarrow4AudioCapability());
- SetCapability(0, 0, new SpeexNarrow5AudioCapability());
- SetCapability(0, 0, new SpeexNarrow6AudioCapability());
- */
- capabilities.Remove(args.GetOptionString('D').Lines());
- capabilities.Reorder(args.GetOptionString('P').Lines());
- // cout << "Codecs (in preference order):n" << setprecision(2) << capabilities << endl;
- return TRUE;
- }
- ///////////////////////////////////////////////////////////////
- C_PCM_RecordFile::C_PCM_RecordFile(C_MyH323Connection & _conn, const PFilePath & _fn, unsigned _callLimit)
- : conn(_conn), fn(_fn), callLimit(_callLimit)
- {
- recordStarted = FALSE;
- timeLimitExceeded = FALSE;
- closed = FALSE;
- dataWritten = FALSE;
- // If the file name ends in .wav then open the output as a WAV file.
- // Otherwise open it as a raw file.
- if ((_fn.Right(4)).ToLower() == ".wav")
- fileclass = new PWAVFile(_fn, PFile::WriteOnly,
- PFile::ModeDefault,PWAVFile::PCM_WavFile);
- else
- fileclass = new PFile(_fn, PFile::WriteOnly);
- }
- void C_PCM_RecordFile::StartRecording()
- {
- PWaitAndSignal mutex(pcmrecordMutex);
- if (recordStarted)
- return;
- PTRACE(1, "Starting recording to " << fn);
- PTime now;
- recordStarted = TRUE;
- finishTime = now + (callLimit * 1000);
- }
- BOOL C_PCM_RecordFile::Close()
- {
- PWaitAndSignal mutex(pcmrecordMutex);
- closed = TRUE;
- return fileclass->Close();
- }
- BOOL C_PCM_RecordFile::Write(const void * buf, PINDEX len)
- {
- // Wait for the mutex, and Signal it at the end of this function
- PWaitAndSignal mutex(pcmrecordMutex);
- // If the record file has been closed, or if the time limit has
- // been exceeded, then return immediatly.
- if (closed || timeLimitExceeded)
- return FALSE;
- if (!recordStarted) {
- DelayFrame(len);
- return TRUE;
- }
- PTime now;
- if ((callLimit != 0) && (now >= finishTime)) {
- PTRACE(1, "Terminating call due to timeout");
- conn.ClearCall();
- timeLimitExceeded = TRUE;
- return TRUE;
- }
- DelayFrame(len);
- dataWritten = TRUE;
- return WriteFrame(buf, len);
- }
- BOOL C_PCM_RecordFile::WriteFrame(const void * buf, PINDEX len)
- {
- //cerr << "Writing PCM " << len << endl;
- return fileclass->Write(buf, len);
- }
- void C_PCM_RecordFile::DelayFrame(PINDEX len)
- {
- delay.Delay(len/16);
- }
- C_PCM_RecordFile::~C_PCM_RecordFile()
- {
- PWaitAndSignal mutex(pcmrecordMutex);
- if (!dataWritten) {
- PTRACE(1, "Deleting " << fn << " as no data recorded");
- fileclass->Remove(fn);
- }
- delete fileclass;
- }
- ///////////////////////////////////////////////////////////////
- // Override some of the PCM_RecordFile functions to write
- // G723.1 data instead of PCM data.
- C_G7231_RecordFile::C_G7231_RecordFile(C_MyH323Connection & _conn, const PFilePath & _fn, unsigned _callLimit)
- : C_PCM_RecordFile(_conn, _fn, _callLimit)
- {
- // If the record file is a .wav file, we need to close the file
- // that PCM_RecordFile will have opened, and reopen it as a G.723.1 Wav file.
- if ((_fn.Right(4)).ToLower() == ".wav") {
- fileclass->Remove(_fn);
- delete fileclass;
- fileclass = new PWAVFile(_fn, PFile::WriteOnly,
- PFile::ModeDefault,PWAVFile::G7231_WavFile);
- }
- }
- BOOL C_G7231_RecordFile::WriteFrame(const void * buf, PINDEX /*len*/)
- {
- int frameLen = G7231_File_Codec::GetFrameLen(*(BYTE *)buf);
- // cerr << "Writing G7231 " << frameLen << endl;
- return fileclass->Write(buf, frameLen);
- }
- void C_G7231_RecordFile::DelayFrame(PINDEX /*len*/)
- {
- // Ignore the len parameter as that is the compressed size.
- // We must delay by the actual sample time.
- delay.Delay((G7231_SAMPLES_PER_BLOCK*2)/16);
- }
- ///////////////////////////////////////////////////////////////
- static BOOL MatchString(const PString & str1, const PString str2)
- {
- if (str1.GetLength() != str2.GetLength())
- return FALSE;
- PINDEX len = str1.GetLength();
- PINDEX i;
- for (i = 0; i < len; i++)
- if ((str1[i] != '?') && (str2[i] != '?') && (str1[i] != str2[i]))
- return FALSE;
- return TRUE;
- }
- static PINDEX FindMatch(const PStringList & list, const PString & key)
- {
- PINDEX maxKeyLen = 0;
- PINDEX i;
- PINDEX keyLen = key.GetLength();
- PINDEX listLen = list.GetSize();
- for (i = 0; i < listLen; i++)
- maxKeyLen = PMAX(maxKeyLen, list[i].GetLength());
- if (keyLen == 0 || maxKeyLen == 0)
- return P_MAX_INDEX;
- if (keyLen > maxKeyLen)
- return P_MAX_INDEX;
- PINDEX len = 1;
- while (len <= keyLen) {
- PString subStr = key.Left(len);
- PINDEX matches = 0;
- PINDEX lastMatch = P_MAX_INDEX;
- PINDEX i;
- // look for a match to the substring
- for (i = 0; i < list.GetSize(); i++) {
- if ((list[i].GetLength() >= keyLen) && MatchString(list[i].Left(len), subStr)) {
- matches++;
- lastMatch = i;
- }
- }
- // if we got ONE match, we have a winner
- if (matches == 1)
- return lastMatch+1;
- // if we have no matches, then there is no point continuing
- if (matches == 0)
- return P_MAX_INDEX;
- // if we have more than one match, try the next char
- len++;
- }
- // too many matches
- return 0;
- }
- C_MyH323Connection::C_MyH323Connection(C_MyH323EndPoint & _ep, unsigned callReference)
- : H323Connection(_ep, callReference), ep(_ep)
- {
- basename = psprintf("%04i%02i%02i_%02i%02i%02i", callStartTime.GetYear(), callStartTime.GetMonth(), callStartTime.GetDay(),
- callStartTime.GetHour(), callStartTime.GetMinute(), callStartTime.GetSecond());
- recordFile = NULL;
- ogmChannel = NULL;
- receiveCodecName = transmitCodecName = "none";
- // SetMaxAudioDelayJitter(150);
- cout << "Opening connection" << endl;
- currentMenu = 0;
- digits = "";
- PConfig config;
- PStringList sections = config.GetSections();
- PINDEX i;
- for (i = 0; i < sections.GetSize(); i++) {
- if (sections[i].Find(MENU_PREFIX) == 0)
- menuNames.AppendString(sections[i]);
- }
- }
- C_MyH323Connection::~C_MyH323Connection()
- {
- cout << "Closing connection" << endl;
- PTime now;
- PTimeInterval interval = now - recordStartTime;
- PString addr = GetControlChannel().GetRemoteAddress();
- PString codecStr = receiveCodecName + "/" + transmitCodecName;
- unsigned duration = (unsigned)((interval.GetMilliSeconds()+999)/1000);
- LogCall(recordFn, addr, GetRemotePartyName(), duration, codecStr, product);
- if ((recordFile!= NULL) && (recordFile->WasRecordStarted()) && !ep.GetRunCmd().IsEmpty()) {
- PString cmdStr = ep.GetRunCmd() &
- recordFn &
- "'" + addr + "'" &
- """ + GetRemotePartyName() + """ &
- PString(PString::Unsigned, duration) &
- """ + codecStr + """ &
- """ + product + """;
- PTRACE(1, "Executing : " << cmdStr);
- system((const char *)cmdStr);
- } else {
- PTRACE(1, "No action to perform at end of record");
- }
- if (ogmChannel != NULL)
- delete ogmChannel;
- if (recordFile != NULL)
- delete recordFile;
- if (ep.GetDeleteAfterRecord()) {
- PTRACE(1, "Removing " << recordFn << " as requested by option");
- PFile::Remove(recordFn);
- }
- }
- H323Connection::AnswerCallResponse
- C_MyH323Connection::OnAnswerCall(const PString & caller,
- const H323SignalPDU & setupPDU,
- H323SignalPDU & /*connectPDU*/)
- {
- product = "Unknown";
- const H225_Setup_UUIE & setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
- const H225_EndpointType & epInfo = setup.m_sourceInfo;
- if (epInfo.HasOptionalField(H225_EndpointType::e_vendor)) {
- const H225_VendorIdentifier & vendorInfo = epInfo.m_vendor;
- if (vendorInfo.HasOptionalField(H225_VendorIdentifier::e_productId))
- product = vendorInfo.m_productId.AsString();
- if (vendorInfo.HasOptionalField(H225_VendorIdentifier::e_versionId))
- product = product + "/" + vendorInfo.m_versionId.AsString();
- }
-
- cout << "Accepting call from " << caller << " using " << product << endl;
- return AnswerCallNow;
- }
- BOOL C_MyH323Connection::OpenAudioChannel(BOOL isEncoding,
- unsigned /* bufferSize */,
- H323AudioCodec & codec)
- {
- codec.SetSilenceDetectionMode(H323AudioCodec::NoSilenceDetection);
- PStringStream codecName;
- codecName << codec;
- PString ogm;
- BOOL isPCM = FALSE;
- if (codec.IsDescendant(G7231_File_Codec::Class())) {
- ogm = ep.GetG7231OGM();
- isPCM = FALSE;
- } else if (codec.IsDescendant(H323_GSM0610Codec::Class())) {
- ogm = ep.GetGSMOGM();
- isPCM = TRUE;
- } else if (codec.IsDescendant(MicrosoftGSMCodec::Class())) {
- ogm = ep.GetGSMOGM();
- isPCM = TRUE;
- } else if (codec.IsDescendant(H323_muLawCodec::Class())) {
- ogm = ep.GetG711OGM();
- isPCM = TRUE;
- } else if (codec.IsDescendant(H323_ALawCodec::Class())) {
- ogm = ep.GetG711OGM();
- isPCM = TRUE;
- } else if (codec.IsDescendant(H323_LPC10Codec::Class())) {
- ogm = ep.GetLPC10OGM();
- isPCM = TRUE;
- } else if (codec.IsDescendant(SpeexCodec::Class())) {
- ogm = ep.GetSPEEXOGM();
- isPCM = TRUE;
- } else {
- cerr << "Unknown codec "" << codecName << endl;
- return FALSE;
- }
- PWaitAndSignal mutex(connMutex);
- if ((recordFile == NULL) && (isEncoding == FALSE)) {
- if (isPCM) {
- if (ep.GetRecordWav() == TRUE)
- recordFn = ep.GetDirectory() + (basename + ".wav");
- else
- recordFn = ep.GetDirectory() + (basename + ".sw");
- recordFile = new C_PCM_RecordFile (*this, recordFn, ep.GetCallLimit());
- } else {
- if (ep.GetRecordWav() == TRUE)
- recordFn = ep.GetDirectory() + (basename + ".wav");
- else
- recordFn = ep.GetDirectory() + (basename + ".g723");
- recordFile = new C_G7231_RecordFile(*this, recordFn, ep.GetCallLimit());
- }
- }
- if ((ogmChannel == NULL) && (isEncoding == TRUE)) {
- if (isPCM)
- ogmChannel = new C_PCM_OGMChannel(*this);
- else
- ogmChannel = new C_G7231_OGMChannel(*this);
- }
- if (isEncoding) {
- if (ep.GetHangupAfterPlay())
- ogmChannel->SetPlayOnce();
- if (ogm.Find("%s"))
- ogm.Replace("%s", e164Number);
- transmitCodecName = codecName;
- if (!StartMenu(0)) {
- if (!PFile::Exists(ogm))
- cerr << "error: cannot find OGM "" << ogm << """ << endl;
- else
- ogmChannel->QueueFile(ogm);
- if (!ep.GetNoRecordG7231())
- ogmChannel->SetRecordTrigger();
- }
- codec.AttachChannel(ogmChannel, FALSE);
- } else {
- receiveCodecName = codecName;
- codec.AttachChannel(recordFile, FALSE);
- }
- return TRUE;
- }
- BOOL C_MyH323Connection::OnStartLogicalChannel(H323Channel & channel)
- {
- if (!H323Connection::OnStartLogicalChannel(channel))
- return FALSE;
- cout << "Started logical channel: ";
- switch (channel.GetDirection()) {
- case H323Channel::IsTransmitter :
- cout << "sending ";
- break;
- case H323Channel::IsReceiver :
- cout << "receiving ";
- break;
- default :
- break;
- }
- cout << channel.GetCapability() << endl;
- return TRUE;
- }
- void C_MyH323Connection::StartRecording()
- {
- recordFile->StartRecording();
- }
- void C_MyH323Connection::OnUserInputString(const PString & value)
- {
- PINDEX i;
- for (i = 0; i < value.GetLength(); i++) {
- OnUserInputChar(value[i]);
- }
- }
- BOOL C_MyH323Connection::StartMenu(int menuNumber)
- {
- digits = "";
- currentMenu = menuNumber;
- PString menuName = psprintf("%s%i", MENU_PREFIX, menuNumber);
- if (menuNames.GetStringsIndex(menuName) == P_MAX_INDEX)
- return FALSE;
- PTRACE(1, "Starting menu " << menuNumber);
- PConfig menu(menuName);
- PString startCmd = menu.GetString("start");
- if (!startCmd.IsEmpty())
- ProcessMenuCmd(startCmd);
- return TRUE;
- }
- BOOL C_MyH323Connection::ProcessMenuCmd(const PString & cmdStr)
- {
- PTRACE(1, "Processing menu cmd " << cmdStr);
- PStringArray tokens = cmdStr.Tokenise(" ", FALSE);
- int len = tokens.GetSize();
- if (len == 0)
- return TRUE;
- PString cmd = tokens[0];
- if ((len >= 2) && (cmd *= "play")) {
- ogmChannel->QueueFile(tokens[1]);
- if (len > 2) {
- cmd = "menu";
- tokens[1] = tokens[2];
- }
- }
- if ((len >= 2) && (cmd *= "menu")) {
- int newMenu = tokens[1].AsInteger();
- if (newMenu != currentMenu)
- StartMenu(newMenu);
- }
- else if (cmd *= "hangup")
- ogmChannel->SetHangupTrigger();
- else if (cmd *= "record")
- ogmChannel->SetRecordTrigger();
- return TRUE;
- }
- void C_MyH323Connection::OnUserInputChar(char ch)
- {
- if (ch == '#')
- digits += '$';
- else
- digits += ch;
- PTRACE(1, "Processing digit string " << digits);
- ogmChannel->FlushQueue();
- PString menuName = psprintf("%s%i", MENU_PREFIX, currentMenu);
- if (menuNames.GetStringsIndex(menuName) == P_MAX_INDEX) {
- PTRACE(1, "Cannot find menu " << menuName);
- StartMenu(0);
- return;
- }
- PConfig menu(menuName);
- PStringList keys = menu.GetKeys();
- PINDEX keyMatch = FindMatch(keys, digits);
- // if key is still ambiguous, then keep collecting
- if (keyMatch == 0)
- return;
- PString cmd;
- if (keyMatch != P_MAX_INDEX) {
- PString key = keys[keyMatch-1];
- PTRACE(1, "Executing cmd for key " << key);
- cmd = menu.GetString(key);
- } else {
- PTRACE(1, "Cannot match cmd " << digits << " in menu " << menuName);
- cmd = menu.GetString("error", "menu 0");
- }
- if (!cmd.IsEmpty()) {
- ProcessMenuCmd(cmd);
- digits = "";
- }
- }
- ///////////////////////////////////////////////////////////////
- /*BOOL CheckWAVFileValid(PWAVFile *chan, int type) {
- // Check the wave file header
- if (!chan->IsValid()) {
- PTRACE(1, chan->GetName() << " wav file header invalid");
- return FALSE;
- }
- // Check the wave file format
- if ( (type == CHECK_PCM) && (chan->GetFormat() != 0x01) ){
- PTRACE(1, chan->GetName() << " is not a PCM format wav file");
- PTRACE(1, "It is format " << chan->GetFormat() );
- return FALSE;
- }
- if ( (type == CHECK_G7231) &&
- ((chan->GetFormat() != 0x42) && (chan->GetFormat() != 0x111)) ){
- PTRACE(1, chan->GetName() << " is not a G.723.1 format wav file");
- PTRACE(1, "It is format " << chan->GetFormat() );
- return FALSE;
- }
- // Check the sample rate for PCM wave files
- if ( (type == CHECK_PCM) &&
- ( (chan->GetSampleRate() != 8000)
- ||(chan->GetChannels() != 1)
- ||(chan->GetSampleSize() != 16) )
- ) {
- PTRACE(1, chan->GetName() << " is not a 16 Bit, Mono, 8000 Hz (8Khz) PCM wav file");
- PTRACE(1, "It is " << chan->GetSampleSize() << " bits, "
- << (chan->GetChannels()==1 ? "mono " : "stereo ")
- << chan->GetSampleRate() << " Hz");
- return FALSE;
- }
- return TRUE;
- }*/
- ///////////////////////////////////////////////////////////////
- C_PCM_OGMChannel::C_PCM_OGMChannel(C_MyH323Connection & _conn)
- : conn(_conn)
- {
- silentCount = 20; // wait 20 frames before playing the OGM
- recordTrigger = FALSE;
- hangupTrigger = FALSE;
- closed = FALSE;
- playOnce = FALSE;
- frameLen = frameOffs = 0;
- }
- void C_PCM_OGMChannel::PlayFile(PFile * chan)
- {
- PWaitAndSignal mutex(chanMutex);
- // if (IsOpen())
- // Close();
- if (!chan->Open(PFile::ReadOnly)) {
- PTRACE(1, "Cannot open file "" << chan->GetName() << """);
- return;
- }
- PTRACE(1, "Playing file "" << chan->GetName() << """);
- totalData = 0;
- SetReadChannel(chan, TRUE);
- }
- BOOL C_PCM_OGMChannel::IsWAVFileValid(PWAVFile *chan) {
- // Check that this is a PCM wave file
- return CheckWAVFileValid(chan, CHECK_PCM);
- }
- BOOL C_PCM_OGMChannel::Read(void * buffer, PINDEX amount)
- {
- PWaitAndSignal mutex(chanMutex);
- // if the channel is closed, then return error
- if (closed)
- return FALSE;
- // Create the frame buffer using the amount of bytes the codec wants to
- // read. Different codecs use different read sizes.
- frameBuffer.SetMinSize(1024);//amount);
- // assume we are returning silence
- BOOL doSilence = TRUE;
- BOOL frameBoundary = FALSE;
- // if still outputting a frame from last time, then keep doing it
- if (frameOffs < frameLen) {
- frameBoundary = AdjustFrame(buffer, amount);
- doSilence = FALSE;
- } else {
- // if we are returning silence frames, then
- if (silentCount > 0)
- silentCount--;
- // if a channel is already open, don't do silence
- else if (GetBaseReadChannel() != NULL)
- doSilence = FALSE;
- // If not in silence and no existing channel, open a new file.
- else {
- PString * str = playQueue.Dequeue();
- if (str != NULL) {
- // check the file extension and open a .wav or a raw (.sw or .g723) file
- if (((*str).Right(4)).ToLower() == ".wav") {
- PWAVFile *chan;
- chan = new PWAVFile(*str, PFile::ReadOnly);
- if (!chan->IsOpen()) {
- PTRACE(1, "Cannot open file "" << chan->GetName() << """);
- delete chan;
- } else {
- if (!IsWAVFileValid(chan) ){
- PTRACE(1, chan->GetName() << " is not a valid wav file");
- delete chan;
- cerr << "wave file is invalid" << endl;
- } else {
- PTRACE(1, "Playing file "" << chan->GetName() << """);
- totalData = 0;
- SetReadChannel(chan, TRUE);
- doSilence = FALSE;
- }
- }
- } else { // raw file (eg .sw)
- PFile *chan;
- chan = new PFile(*str);
- if (!chan->Open(PFile::ReadOnly)) {
- PTRACE(1, "Cannot open file "" << chan->GetName() << """);
- delete chan;
- } else {
- PTRACE(1, "Playing file "" << chan->GetName() << """);
- totalData = 0;
- SetReadChannel(chan, TRUE);
- doSilence = FALSE;
- }
- }
- delete str;
- }
- }
-
- // if not doing silence, try and read from the file
- if (!doSilence) {
-
- if (ReadFrame(amount)) {
- frameBoundary = AdjustFrame(buffer, amount);
- totalData += amount;
-
- } else {
- PTRACE(1, "Finished playing " << totalData << " bytes");
- //closed = TRUE;
-
- PIndirectChannel::Close();
- silentCount = 5; // always do 5 frames of silence after every file
-
- // hangup if required
- if (hangupTrigger || playOnce)
- conn.ClearCall();
-
- // trigger record if required
- else if (recordTrigger) {
- if ((playQueue.GetSize() == 0) && (GetBaseReadChannel() == NULL))
- conn.StartRecording();
- }
-
- // no silence
- doSilence = TRUE;
- }
- }
- }
-
- // start silence frame if required
- if (doSilence) {
- CreateSilenceFrame(amount);
- frameBoundary = AdjustFrame(buffer, amount);
- }
- // delay to synchronise to frame boundary
- if (frameBoundary)
- Synchronise(amount);
- return TRUE;
- }
- BOOL C_PCM_OGMChannel::Close()
- {
- PWaitAndSignal mutex(chanMutex);
- closed = TRUE;
- PIndirectChannel::Close();
- return TRUE;
- }
- void C_PCM_OGMChannel::SetRecordTrigger()
- {
- PWaitAndSignal mutex(chanMutex);
- recordTrigger = TRUE;
- if ((playQueue.GetSize() == 0) && (GetBaseReadChannel() == NULL))
- conn.StartRecording();
- }
- void C_PCM_OGMChannel::SetHangupTrigger()
- {
- PWaitAndSignal mutex(chanMutex);
- hangupTrigger = TRUE;
- if (GetBaseReadChannel() == NULL)
- conn.ClearCall();
- }
- void C_PCM_OGMChannel::QueueFile(const PString & fn)
- {
- PWaitAndSignal mutex(chanMutex);
- PTRACE(1, "Enqueueing file " << fn << " for playing");
- playQueue.Enqueue(new PString(fn));
- }
- void C_PCM_OGMChannel::FlushQueue()
- {
- PWaitAndSignal mutex(chanMutex);
- if (GetBaseReadChannel() != NULL) {
- PIndirectChannel::Close();
- if (hangupTrigger)
- conn.ClearCall();
- else if (recordTrigger)
- conn.StartRecording();
- }
- PString * str;
- while ((str = playQueue.Dequeue()) != NULL)
- delete str;
- }
- BOOL C_PCM_OGMChannel::AdjustFrame(void * buffer, PINDEX amount)
- {
- if ((frameOffs + amount) > frameLen) {
- cerr << "Reading past end of frame:offs=" << frameOffs << ",amt=" << amount << ",len=" << frameLen << endl;
- return TRUE;
- }
- //PAssert((frameOffs + amount) <= frameLen, "Reading past end of frame");
- memcpy(buffer, frameBuffer.GetPointer()+frameOffs, amount);
- frameOffs += amount;
- lastReadCount = amount;
- return frameOffs == frameLen;
- }
- void C_PCM_OGMChannel::Synchronise(PINDEX amount)
- {
- ogm_delay.Delay(amount / 16);
- }
- BOOL C_PCM_OGMChannel::ReadFrame(PINDEX amount)
- {
- frameOffs = 0;
- frameLen = amount;
- BOOL result = PIndirectChannel::Read(frameBuffer.GetPointer(), frameLen);
- // if we did not read a full frame of audio, fill the end of the
- // frame with zeros.
- PINDEX count = GetLastReadCount();
- if (count < frameLen)
- memset(frameBuffer.GetPointer()+count, 0, frameLen-count);
- return result;
- }
- void C_PCM_OGMChannel::CreateSilenceFrame(PINDEX amount)
- {
- frameOffs = 0;
- frameLen = amount;
- memset(frameBuffer.GetPointer(), 0, frameLen);
- }
- ///////////////////////////////////////////////////////////////
- C_G7231_OGMChannel::C_G7231_OGMChannel(C_MyH323Connection & conn)
- : C_PCM_OGMChannel(conn)
- {
- }
- void C_G7231_OGMChannel::Synchronise(PINDEX /*amount*/)
- {
- ogm_delay.Delay(30);
- }
- BOOL C_G7231_OGMChannel::ReadFrame(PINDEX /*amount*/)
- {
- if (!PIndirectChannel::Read(frameBuffer.GetPointer(), 1))
- return FALSE;
- frameOffs = 0;
- frameLen = G7231_File_Codec::GetFrameLen(frameBuffer[0]);
- return PIndirectChannel::Read(frameBuffer.GetPointer()+1, frameLen-1);
- }
- void C_G7231_OGMChannel::CreateSilenceFrame(PINDEX /*amount*/)
- {
- frameOffs = 0;
- frameLen = 4;
- frameBuffer[0] = 2;
- memset(frameBuffer.GetPointer()+1, 0, 3);
- }
- BOOL C_G7231_OGMChannel::IsWAVFileValid(PWAVFile *chan) {
- // Check that this is a G.723.1 wave file
- return CheckWAVFileValid(chan, CHECK_G7231);
- }
- ///////////////////////////////////////////////////////////////