main.cxx
上传用户:wgl386701
上传日期:2007-01-06
资源大小:22k
文件大小:31k
- /*
- * main.cxx
- *
- * PWLib application source file for Voxilla
- *
- * A H.323 "net telephone" application.
- *
- * Copyright (c) 1993-1998 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 of this code were written with the assisance of funding from
- * Vovida Networks, Inc. http://www.vovida.com.
- *
- * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
- * All Rights Reserved.
- *
- * Contributor(s): ______________________________________.
- *
- * $Log: main.cxx,v $
- * Revision 1.24 2000/06/20 02:38:27 robertj
- * Changed H323TransportAddress to default to IP.
- *
- * Revision 1.23 2000/06/17 09:14:52 robertj
- * Added setting of closed flag when closing OGM.
- *
- * Revision 1.22 2000/05/25 13:25:47 robertj
- * Fixed incorrect "save" parameter specification.
- *
- * Revision 1.21 2000/05/25 12:06:17 robertj
- * Added PConfigArgs class so can save program arguments to config files.
- *
- * Revision 1.20 2000/05/11 11:47:11 robertj
- * Fixed alpha linux GNU compiler problems.
- *
- * Revision 1.19 2000/05/10 05:14:25 robertj
- * Changed capabilities so has a function to get name of codec, instead of relying on PrintOn.
- *
- * Revision 1.18 2000/05/09 11:22:15 craigs
- * Fixed problems caused by new jitter buffer code
- * and fixed OGM problems
- *
- * Revision 1.17 2000/05/09 02:41:32 craigs
- * Added extra debugging, and fixed problems with OGM in non-IVR mode
- *
- * Revision 1.16 2000/04/26 03:18:38 craigs
- * Fixed problem when GSM specified as preferred codec
- *
- * Revision 1.15 2000/04/25 23:34:22 craigs
- * Added lots of new code, including outgoing and incoming
- * multiplexors, and the start of an IVR system
- *
- * Revision 1.14 2000/01/13 04:03:45 robertj
- * Added video transmission
- *
- * Revision 1.13 2000/01/07 08:28:09 robertj
- * Additions and changes to line interface device base class.
- *
- * Revision 1.12 1999/12/10 01:44:46 craigs
- * Added ability to set interface
- *
- * Revision 1.11 1999/12/01 04:38:25 robertj
- * Added gatekeeper support to OpenAM
- *
- * Revision 1.10 1999/11/11 00:27:49 robertj
- * Changed OnAnswerCall() call back function to allow for asyncronous response.
- *
- * Revision 1.9 1999/11/06 13:27:48 craigs
- * Added extra output and changed for new library changes
- *
- * Revision 1.8 1999/10/29 10:57:04 robertj
- * Added answering machine project.
- *
- * Revision 1.7 1999/10/24 12:50:37 craigs
- * Fixed G723.1 capability, and added ability for discrete OGMs
- *
- * Revision 1.6 1999/10/24 08:24:56 craigs
- * Added GSM capability back in
- *
- * Revision 1.5 1999/10/24 08:19:58 craigs
- * Fixed problem that caused crash when unknown codecs used
- *
- * Revision 1.4 1999/10/24 03:29:07 craigs
- * Fixed problem with -h parsing
- *
- * Revision 1.3 1999/10/24 03:08:49 craigs
- * Fixed problem with recording zero length messages, and added autodelete of files
- *
- * Revision 1.2 1999/10/22 09:56:24 craigs
- * Fixed various compile warnings
- *
- * Revision 1.1 1999/10/11 00:15:18 craigs
- * Initial version
- *
- */
- #include <ptlib.h>
- #include <ptlib/pipechan.h>
- #include "main.h"
- #include "version.h"
- PCREATE_PROCESS(OpenAm);
- #define new PNEW
- #define DEFAULT_MSG_LIMIT 30
- #define DEFAULT_CALL_LOG "call_log.txt"
- #define G7231_BLOCK_SIZE 24
- #define G7231_SAMPLES_PER_BLOCK 240
- #define G7231_BANDWIDTH 63
- #define MENU_PREFIX "UserMenu-"
- static PMutex logMutex;
- static PTextFile logFile;
- static PFilePath logFilename = DEFAULT_CALL_LOG;
- static PString G7231Ext = ".g723";
- static PString PCMExt = ".sw";
- 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 + """);
- }
- ///////////////////////////////////////////////////////////////
- OpenAm::OpenAm()
- : PProcess("OpenH323 Project", "OpenAm",
- MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
- {
- }
- OpenAm::~OpenAm()
- {
- }
- void OpenAm::Main()
- {
- cout << GetName()
- << " Version " << GetVersion(TRUE)
- << " by " << GetManufacturer()
- << " on " << GetOSClass() << ' ' << GetOSName()
- << " (" << GetOSVersion() << '-' << GetOSHardware() << ")nn";
- //PArgList & args = GetArguments();
- PConfigArgs args(GetArguments());
- args.Parse(
- "d-directory:"
- "g-gatekeeper:" "n-no-gatekeeper."
- "-require-gatekeeper." "-no-require-gatekeeper."
- "-g7231message:" "-no-g7231message."
- "-g711message:" "-no-g711message."
- "-gsmmessage:" "-no-gsmmessage."
- "-no-recordg7231."
- "-gsm." "-no-gsm."
- "-g711-ulaw." "-no-g711-ulaw."
- "-g711-alaw." "-no-g711-alaw."
- "-g7231." "-no-g7231."
- "h-help."
- "i-interface:" "-no-interface."
- "k-kill." "-no-kill."
- "l-limit:" "-no-limit."
- "m-pcmmessage:" "-no-message."
- #if PTRACING
- "o-output:"
- #endif
- "r-run:" "-no-run."
- "-save."
- #if PTRACING
- "t-trace."
- #endif
- "u-username:" "-no-username."
- , FALSE);
- #if PTRACING
- PTrace::SetOptions(PTrace::Timestamp | PTrace::Thread);
- PTrace::SetLevel(args.GetOptionCount('t'));
- if (args.HasOption('o')) {
- /* This is a bit tricky. We allocate the file for tracing on the heap, and
- we never actually deallocate it. So it come up as a leak on exit if
- memory checking is on. We cannot deallocate it as during termination
- some PTRACE's may get executed and attempt to trace to a closed (and
- deleted!) file object which crashes. Not good.
- */
- PTextFile * output = new PTextFile;
- if (output->Open(args.GetOptionString('o'), PFile::WriteOnly))
- PTrace::SetStream(output);
- else {
- cout << "Warning: could not open trace output file ""
- << args.GetOptionString('o') << '"' << endl;
- delete output;
- }
- }
- PTRACE(1, GetName()
- << " Version " << GetVersion(TRUE)
- << " by " << GetManufacturer()
- << " on " << GetOSClass() << ' ' << GetOSName()
- << " (" << GetOSVersion() << '-' << GetOSHardware() << ')');
- #endif
- if (args.HasOption('h')) {
- cout << "Usage : " << GetName() << " [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"
- " -r --run cmd : Run this command after each recorded messagen"
- " -k --kill : Kill recorded files after user commandn"
- " -u --username str : Set the local endpoint name to strn"
- " -i --interface ip : Bind to a specific interfacen"
- " -g --gatekeeper host: Specify gatekeeper host.n"
- " -n --no-gatekeeper : Disable gatekeeper discovery.n"
- " --require-gatekeeper: Exit if gatekeeper discovery fails.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");
- #ifdef HAS_CMDS
- if (args.GetCount() > 0) {
- if (args[0] *= "record")
- RecordFile(args);
- else if (args[0] *= "play")
- PlayFile(args);
- else
- 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";
- 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 |= 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 |= MyH323EndPoint::DeleteAfterRecord;
- }
-
- MyH323EndPoint endpoint(callLimit, runCmd, dir, flags);
- PString userName = "OpenH323 Answering Machine v" + GetVersion();
- if (args.HasOption('u'))
- userName = args.GetOptionString('u');
- endpoint.SetLocalUserName(userName);
- BOOL g7231Disable = args.HasOption("no-g7231");
- BOOL gsmDisable = args.HasOption("no-gsm");
- BOOL ulaw64Disable = args.HasOption("no-g711-ulaw");
- if (g7231Disable && gsmDisable && ulaw64Disable) {
- cerr << "Cannot disable all codecs - please enable one of GSM, G723.1 or G.711 uLaw64" << endl;
- return;
- }
- H323Capability * g7231 = NULL;
- H323Capability * gsm = NULL;
- H323Capability * ulaw64 = NULL;
- // get G723.1 OGM
- PString g7231Ogm;
- if (!g7231Disable) {
- if (args.HasOption("g7231message")) {
- PFilePath fn = g7231Ogm = args.GetOptionString("g7231message");
- if (!PFile::Exists(fn + G7231Ext)) {
- cout << "warning: cannot open G723.1 OGM file "" << (fn + G7231Ext) << """ << endl;
- g7231Ogm = "";
- }
- }
- if (g7231Ogm.IsEmpty())
- cout << "No G.723.1 outgoing message setn";
- else {
- cout << "Using "" << (g7231Ogm + G7231Ext) << "" as G.723.1 outgoing messagen";
- endpoint.SetG7231OGM(g7231Ogm);
- }
- g7231 = new G7231_File_Capability;
- if (args.HasOption("g7231"))
- endpoint.AddCapability(g7231);
- }
- // get PCM OGM message which will do for GSM and G711
- PString pcmOgm;
- if (args.HasOption('m'))
- pcmOgm = args.GetOptionString('m');
- // get GSM OGM message
- PString gsmOgm = pcmOgm;
- if (!gsmDisable) {
- if (args.HasOption("gsmmessage"))
- gsmOgm = args.GetOptionString("gsmmessage");
- PFilePath fn = gsmOgm;
- if (!PFile::Exists(fn + PCMExt)) {
- cout << "warning: cannot open GSM OGM file "" << (fn + PCMExt) << """ << endl;
- gsmOgm = "";
- }
- if (gsmOgm.IsEmpty())
- cout << "No GSM outgoing message setn";
- else {
- cout << "Using "" << gsmOgm << "" as GSM outgoing messagen";
- endpoint.SetGSMOGM(gsmOgm);
- }
- gsm = new H323_GSM0610Capability;
- if (args.HasOption("gsm"))
- endpoint.AddCapability(gsm);
- }
- // get G.711 OGM message
- PString g711Ogm = pcmOgm;
- if (!ulaw64Disable) {
- if (args.HasOption("g711message"))
- g711Ogm = args.GetOptionString("g711message");
- PFilePath fn = g711Ogm;
- if (!PFile::Exists(fn + PCMExt)) {
- cout << "warning: cannot open G711 OGM file "" << (fn + PCMExt) << """ << endl;
- g711Ogm = "";
- }
- if (g711Ogm.IsEmpty())
- cout << "No G711 outgoing message setn";
- else {
- cout << "Using "" << g711Ogm << "" as G.711 outgoing messagen";
- endpoint.SetG711OGM(g711Ogm);
- }
- ulaw64 = new H323_G711Capability(H323_G711Capability::muLaw, H323_G711Capability::At64k);
- if (args.HasOption("g711-ulaw"))
- endpoint.AddCapability(ulaw64);
- }
- if ((g7231 == NULL) && (gsm == NULL) && (ulaw64 == NULL)) {
- cerr << "Cannot disable all capabilites - please enable one of GSM, G723.1 or G.711 uLaw64" << endl;
- return;
- }
- if (g7231 != NULL)
- endpoint.SetCapability(0, 0, g7231);
- if (gsm != NULL)
- endpoint.SetCapability(0, 0, gsm);
- if (ulaw64 != NULL)
- endpoint.SetCapability(0, 0, ulaw64);
- // start the H.323 listener
- H323ListenerTCP * listener;
- if (args.GetOptionString('i').IsEmpty())
- listener = new H323ListenerTCP(endpoint);
- else {
- PIPSocket::Address interfaceAddress(args.GetOptionString('i'));
- listener = new H323ListenerTCP(endpoint, interfaceAddress);
- }
- if (!endpoint.StartListener(listener)) {
- cout << "Could not open H.323 listener port on "
- << listener->GetListenerPort() << endl;
- 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;
- }
- }
- endpoint.ListenForIncomingCalls();
- endpoint.AwaitTermination();
- }
- ///////////////////////////////////////////////////////////////
- G7231_File_Capability::G7231_File_Capability()
- : H323AudioCapability(12*G7231_BLOCK_SIZE, 4*G7231_BLOCK_SIZE)
- {
- }
- PString G7231_File_Capability::GetFormatName() const
- {
- return "G723.1";
- }
- BOOL G7231_File_Capability::OnSendingPDU(H245_AudioCapability & cap, unsigned packetSize) const
- {
- // set the choice to the correct type
- cap.SetTag(GetSubType());
- // get choice data
- H245_AudioCapability_g7231 & g7231 = cap;
- // max number of audio frames per PDU we want to send
- g7231.m_maxAl_sduAudioFrames = packetSize; //G7231_BLOCK_SIZE;
- // no silence suppression
- g7231.m_silenceSuppression = FALSE;
- return TRUE;
- }
- BOOL G7231_File_Capability::OnReceivedPDU(const H245_AudioCapability & cap, unsigned & packetSize)
- {
- const H245_AudioCapability_g7231 & g7231 = cap;
- packetSize = g7231.m_maxAl_sduAudioFrames*G7231_BLOCK_SIZE;
- return TRUE;
- }
- PObject * G7231_File_Capability::Clone() const
- {
- return new G7231_File_Capability();
- }
- H323Codec * G7231_File_Capability::CreateCodec(H323Codec::Direction direction) const
- {
- return new G7231_File_Codec(direction);
- }
- ///////////////////////////////////////////////////////////////
- G7231_File_Codec::G7231_File_Codec(Direction dir)
- : H323AudioCodec(dir, G7231_SAMPLES_PER_BLOCK)
- {
- rtpPayloadType = RTP_DataFrame::G7231;
- }
- BOOL G7231_File_Codec::Read(BYTE * buffer, unsigned & length, RTP_DataFrame &)
- {
- if (rawDataChannel == NULL)
- return FALSE;
-
- BOOL stat = rawDataChannel->Read(buffer, G7231_BLOCK_SIZE);
- if (!stat)
- return FALSE;
- if (rawDataChannel->GetLastReadCount() == 0)
- length = 0;
- else
- length = G7231_BLOCK_SIZE;
- return TRUE;
- }
- BOOL G7231_File_Codec::Write(const BYTE * buffer, unsigned length, const RTP_DataFrame & /* rtp */, unsigned & writtenLength)
- {
- writtenLength = G7231_BLOCK_SIZE;
- if (length == 0)
- return TRUE;
- return rawDataChannel->Write(buffer, writtenLength);
- }
- unsigned G7231_File_Codec::GetBandwidth() const { return G7231_BANDWIDTH; }
-
- ///////////////////////////////////////////////////////////////
- MyH323EndPoint::MyH323EndPoint(unsigned _callLimit,
- const PString & _runCmd,
- const PDirectory & _dir,
- int _flags)
- : callLimit(_callLimit), runCmd(_runCmd), dir(_dir), flags(_flags)
- {
- }
- H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference)
- {
- return new MyH323Connection(*this, callReference);
- }
- void MyH323EndPoint::ListenForIncomingCalls()
- {
- cout << "Waiting for incoming calls for "" << GetLocalUserName() << '"' << endl;
- }
- void MyH323EndPoint::AwaitTermination()
- {
- for (;;) {
- PThread::Current()->Sleep(5000);
- }
- }
- ///////////////////////////////////////////////////////////////
- RecordFile::RecordFile(MyH323Connection & _conn, const PFilePath & _fn, unsigned _callLimit)
- : PFile(_fn, PFile::WriteOnly), conn(_conn), fn(_fn), callLimit(_callLimit)
- {
- recordStarted = FALSE;
- closed = FALSE;
- }
- void RecordFile::StartRecording()
- {
- if (recordStarted)
- return;
- PTRACE(1, "Starting recording to " << fn);
- PTime now;
- recordStarted = TRUE;
- finishTime = now + (callLimit * 1000);
- }
- BOOL RecordFile::Close()
- {
- closed = TRUE;
- return PFile::Close();
- }
- BOOL RecordFile::Write(const void * buf, PINDEX len)
- {
- if (closed)
- return FALSE;
- if (!recordStarted)
- return TRUE;
- BOOL stat = PFile::Write(buf, len);
- PTime now;
- if ((callLimit == 0) || (now <= finishTime))
- PThread::Current()->Sleep(((int)len / 2) / 8);
- else {
- PTRACE(1, "Terminating call due to timeout");
- conn.ClearCall();
- }
- return stat;
- }
- RecordFile::~RecordFile()
- {
- if (!recordStarted) {
- PTRACE(1, "Deleting " << fn << " as no data recorded");
- PFile::Remove(fn);
- }
- }
- ///////////////////////////////////////////////////////////////
- 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;
- }
- MyH323Connection::MyH323Connection(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";
- 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]);
- }
- }
- MyH323Connection::~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 (recordFile != NULL)
- delete recordFile;
- if (ep.GetDeleteAfterRecord()) {
- PTRACE(1, "Removing " << recordFn << " as requested by option");
- PFile::Remove(recordFn);
- }
- }
- H323Connection::AnswerCallResponse
- 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 MyH323Connection::OpenAudioChannel(BOOL isEncoding, unsigned /* bufferSize */, H323AudioCodec & codec)
- {
- codec.SetSilenceDetectionMode(H323AudioCodec::NoSilenceDetection);
- PStringStream codecName;
- codecName << codec;
- PString ext;
- PString ogm;
- BOOL isPCM = FALSE;
- if (codec.IsDescendant(G7231_File_Codec::Class())) {
- ext = ".g723";
- ogm = ep.GetG7231OGM();
- isPCM = FALSE;
- } else if (codec.IsDescendant(H323_GSM0610Codec::Class())) {
- ogm = ep.GetGSMOGM();
- ext = PCMExt;
- isPCM = TRUE;
- } else if (codec.IsDescendant(H323_muLawCodec::Class())) {
- ogm = ep.GetG711OGM();
- ext = PCMExt;
- isPCM = TRUE;
- } else {
- cerr << "Unknown codec "" << codecName << endl;
- return FALSE;
- }
- PWaitAndSignal mutex(connMutex);
- if (recordFile == NULL) {
- recordFn = ep.GetDirectory() + (basename + ext);
- recordFile = new RecordFile(*this, recordFn, ep.GetCallLimit());
- }
- if (ogmChannel == NULL) {
- ogmChannel = new OGMChannel(*this);;
- }
- if (isEncoding) {
- transmitCodecName = codecName;
- ogmChannel->SetIsPCM(isPCM);
- ogmChannel->SetExtension(ext);
- if (!StartMenu(0)) {
- if (!PFile::Exists(ogm + ext))
- cerr << "error: cannot find OGM "" << (ogm + ext) << """ << endl;
- else
- ogmChannel->QueueFile(ogm);
- if (!ep.GetNoRecordG7231())
- ogmChannel->SetRecordTrigger();
- }
- codec.AttachChannel(ogmChannel, FALSE);
- } else {
- receiveCodecName = codecName;
- codec.AttachChannel(recordFile, FALSE);
- }
- return TRUE;
- }
- BOOL 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 MyH323Connection::StartRecording()
- {
- recordFile->StartRecording();
- }
- void MyH323Connection::OnUserInputString(const PString & value)
- {
- PINDEX i;
- for (i = 0; i < value.GetLength(); i++) {
- OnUserInputChar(value[i]);
- }
- }
- BOOL 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 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 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 = "";
- }
- }
- ///////////////////////////////////////////////////////////////
- OGMChannel::OGMChannel(MyH323Connection & _conn)
- : conn(_conn)
- {
- lastTime = PTime();
- silentCount = 20;
- recordTrigger = FALSE;
- hangupTrigger = FALSE;
- closed = FALSE;
- }
- void 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);
- }
- void OGMChannel::CreateSilence(void * buffer, PINDEX amount)
- {
- if (!isPCM)
- lastReadCount = 0;
- else {
- memset(buffer, 0, amount);
- lastReadCount = amount;
- }
- }
- BOOL OGMChannel::Read(void * buffer, PINDEX amount)
- {
- PWaitAndSignal mutex(chanMutex);
- if (closed)
- return FALSE;
- BOOL doSilence = TRUE;
- if (silentCount > 0) {
- silentCount--;
- } else {
- if (GetBaseReadChannel() != NULL)
- doSilence = FALSE;
- else {
- PString * str = playQueue.Dequeue();
- if (str != NULL) {
- PFile * chan = new PFile(*str + ext);
- delete 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;
- }
- }
- }
- }
- if (!doSilence) {
- if (PIndirectChannel::Read(buffer, amount))
- totalData += amount;
- else {
- PTRACE(1, "Finished playing " << totalData << " bytes");
- closed = TRUE;
- PIndirectChannel::Close();
- silentCount = 5;
- if (hangupTrigger)
- conn.ClearCall();
- else if (recordTrigger)
- conn.StartRecording();
- doSilence = TRUE;
- }
- }
- if (doSilence)
- CreateSilence(buffer, amount);
- //PThread::Current()->Sleep(amount / 8);
- return TRUE;
- }
- BOOL OGMChannel::Close()
- {
- PWaitAndSignal mutex(chanMutex);
- closed = TRUE;
- PIndirectChannel::Close();
- return TRUE;
- }
- void OGMChannel::SetRecordTrigger()
- {
- PWaitAndSignal mutex(chanMutex);
- recordTrigger = TRUE;
- if ((playQueue.GetSize() == 0) && (GetBaseReadChannel() == NULL))
- conn.StartRecording();
- }
- void OGMChannel::SetHangupTrigger()
- {
- PWaitAndSignal mutex(chanMutex);
- hangupTrigger = TRUE;
- if (GetBaseReadChannel() == NULL)
- conn.ClearCall();
- }
- void OGMChannel::QueueFile(const PString & fn)
- {
- PWaitAndSignal mutex(chanMutex);
- PTRACE(1, "Enqueueing file " << (fn + ext) << " for playing");
- playQueue.Enqueue(new PString(fn));
- }
- void OGMChannel::FlushQueue()
- {
- PWaitAndSignal mutex(chanMutex);
- if (GetBaseReadChannel() != NULL) {
- PIndirectChannel::Close();
- if (hangupTrigger)
- conn.ClearCall();
- else if (recordTrigger)
- conn.StartRecording();
- }
- PString * str;
- for (;;) {
- str = playQueue.Dequeue();
- if (str == NULL)
- break;
- delete str;
- }
- }
- // End of File ///////////////////////////////////////////////////////////////