📄 h323.cxx
字号:
/*
* h323.cxx
*
* H.323 routines for a simple MCU
*
* Copyright (C) 2000 Equivalence Pty. Ltd.
* Copyright (C) 2004 Post Increment
*
* 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 ths code were written by by Post Increment (http://www.postincrement.com)
* with the assistance of funding from Stonevoice, slc. http://www.stonevoice.com
*
* Portions of this code were written by Post Increment (http://www.postincrement.com)
* with the assistance of funding from Citron Networks (http://www.citron.com.tw)
*
* Contributor(s): Derek J Smithies (derek@indranet.co.nz)
* Craig Southeren (craig@postincrement.com)
*
* $Log: h323.cxx,v $
* Revision 1.2 2007/11/07 04:03:25 willamowius
* fix compile on gcc
*
* Revision 1.1 2007/10/17 19:44:30 shorne
* Initial Commit
*
* Revision 2.7.2.2 2007/08/16 20:29:01 shorne
* Better Gatekeeper anf Gateway prefix support
*
* Revision 2.7.2.1 2007/02/06 11:41:26 shorne
* Updates for OpenH323 Video Plugins
*
* Revision 2.7 2006/08/07 06:18:22 csoutheren
* Fix detection of MCU members
* Add auto-removal of conferences only containing MCU members
*
* Revision 2.6 2006/08/02 06:24:53 csoutheren
* Add provision for recording input audio
*
* Revision 2.5 2006/07/21 08:01:40 csoutheren
* Fixed conference member detect
* Re-factored video mixer code slightly
*
* Revision 2.4 2006/07/21 05:52:51 csoutheren
* Add flag to indicate if remote endpoint is an MCU
*
* Revision 2.3 2006/07/21 05:08:03 csoutheren
* Stability fixes and more inline documentation
* Thanks to Paolo Amadini of Stonevoice
*
* Revision 2.2 2006/06/21 06:11:36 csoutheren
* Fixes for latest pwlib
*
* Revision 2.1 2006/06/09 04:39:59 csoutheren
* Migrated VideoBranch to main trunk
*
* Revision 1.1.2.8 2006/06/06 08:24:16 csoutheren
* Added support for echo test room
* Fix problem with using high frame rates
*
* Revision 1.1.2.7 2006/05/31 08:48:02 csoutheren
* Fixed crash on second call when entry/exit files do not exist
* Fix crash when Cisco HOLD used. Thanks to Christian Bongiovanni of Stonevoice
*
* Revision 1.1.2.6 2006/04/26 13:09:08 csoutheren
* Fix problem when connecting file not available
* Add optional time limit for rooms
*
* Revision 1.1.2.5 2006/04/18 03:05:09 csoutheren
* Fix video mix problem with > 3 members
* Add test room
*
* Revision 1.1.2.4 2006/04/06 08:20:29 csoutheren
* Retyped conference member identifier to epxlicit type
* Added support for H.245 terminal added and terminal left
*
* Revision 1.1.2.3 2006/04/06 01:11:16 csoutheren
* Latest sources include
* - premedia blanking and optional image display
* - ablity to defer conference join for authentication if required
* - more bulletproofing on conference join
* - new video copy/fill functions
*
* Revision 1.1.2.2 2006/04/06 00:50:30 csoutheren
* Latest changes (more to come)
*
* Revision 1.1.2.1 2006/03/28 05:13:38 csoutheren
* Normalised file headers
* Fixed problem with QCIF video
* Seperated H.323 and MCU process functions into seperate files
*
*/
#include <ptlib.h>
#include <ptlib/video.h>
#include "version.h"
#include "mcu.h"
#include "h323.h"
#include <h323pdu.h>
#if OPENMCU_VIDEO
const unsigned int DefaultVideoFrameRate = 10;
const unsigned int DefaultVideoQuality = 10;
static const char EnableVideoKey[] = "Enable video";
static const char VideoFrameRateKey[] = "Video frame rate";
static const char VideoQualityKey[] = "Video quality";
#endif // OPENMCU_VIDEO
static const char InterfaceKey[] = "Interface";
static const char LocalUserNameKey[] = "Local User Name";
static const char GatekeeperUserNameKey[] = "Gatekeeper Username";
static const char GatekeeperAliasKey[] = "Gatekeeper Room Names";
static const char GatekeeperPasswordKey[] = "Gatekeeper Password";
static const char GatekeeperPrefixesKey[] = "Gatekeeper Prefixes";
static const char GatekeeperModeKey[] = "Gatekeeper Mode";
static const char GatekeeperKey[] = "Gatekeeper";
static const char DisableCodecsKey[] = "Disable codecs";
static const char * GKModeLabels[] = {
"No gatekeeper",
"Find gatekeeper",
"Use gatekeeper",
};
enum {
Gatekeeper_None,
Gatekeeper_Find,
Gatekeeper_Explicit
};
#define GKMODE_LABEL_COUNT (sizeof(GKModeLabels)/sizeof(char *))
#define new PNEW
///////////////////////////////////////////////////////////////
void SpliceMacro(PString & text, const PString & token, const PString & value)
{
PRegularExpression RegEx("<?!--#status[ \t\r\n]+" + token + "[ \t\r\n]*-->?",
PRegularExpression::Extended|PRegularExpression::IgnoreCase);
PINDEX pos, len;
while (text.FindRegEx(RegEx, pos, len))
text.Splice(value, pos, len);
}
///////////////////////////////////////////////////////////////
OpenMCUH323EndPoint::OpenMCUH323EndPoint(ConferenceManager & _conferenceManager)
: conferenceManager(_conferenceManager)
{
#if OPENMCU_VIDEO
terminalType = e_MCUWithAVMP;
enableVideo = TRUE;
videoRate = DefaultVideoFrameRate;
#else
terminalType = e_MCUWithAudioMP;
#endif
gkAlias = PString();
}
void OpenMCUH323EndPoint::Initialise(PConfig & cfg, PConfigPage * rsrc)
{
#ifdef HAS_AEC
SetAECEnabled(FALSE);
#endif
///////////////////////////////////////////
// Listeners
PString defaultInterface = "*:1720";
H323TransportAddressArray interfaces;
PINDEX arraySize = cfg.GetInteger(PString(InterfaceKey) + " Array Size");
if (arraySize == 0)
StartListener(defaultInterface);
else {
for (int i = 0; i < arraySize; i++)
interfaces.Append(new H323TransportAddress(cfg.GetString(psprintf("%s %u", InterfaceKey, i+1), "")));
StartListeners(interfaces);
}
rsrc->Add(new PHTTPFieldArray(new PHTTPStringField(cfg.GetDefaultSection() + "\\" + InterfaceKey, InterfaceKey, 20, defaultInterface), FALSE));
if (listeners.IsEmpty()) {
PSYSTEMLOG(Fatal, "Main\tCould not open H.323 Listener");
}
AliasList.RemoveAll();
localAliasNames.RemoveAll();
//////////////////////////////////////////////////////
// Gatekeeper mode
PStringArray labels(GKMODE_LABEL_COUNT, GKModeLabels);
PINDEX idx = labels.GetStringsIndex(cfg.GetString(GatekeeperModeKey, labels[0]));
PINDEX gkMode = (idx == P_MAX_INDEX) ? 0 : idx;
rsrc->Add(new PHTTPRadioField(GatekeeperModeKey, labels, gkMode));
// Gatekeeper
PString gkName = cfg.GetString(GatekeeperKey);
rsrc->Add(new PHTTPStringField(GatekeeperKey, 25, gkName));
// Gatekeeper UserName
PString gkUserName = cfg.GetString(GatekeeperUserNameKey,"MCU");
if (gkMode == Gatekeeper_None ) {
// Local alias name for H.323 endpoint
SetLocalUserName(cfg.GetString(LocalUserNameKey, OpenMCU::Current().GetName() + " v" + OpenMCU::Current().GetVersion()));
} else {
SetLocalUserName(gkUserName);
}
rsrc->Add(new PHTTPStringField(GatekeeperUserNameKey, 25, gkUserName));
AliasList.AppendString(gkUserName);
// Gatekeeper password
PString gkPassword = PHTTPPasswordField::Decrypt(cfg.GetString(GatekeeperPasswordKey));
SetGatekeeperPassword(gkPassword);
rsrc->Add(new PHTTPPasswordField(GatekeeperPasswordKey, 25, gkPassword));
// Gatekeeper Alias
gkAlias = cfg.GetString(GatekeeperAliasKey,"MCU*");
rsrc->Add(new PHTTPStringField(GatekeeperAliasKey, 25, gkAlias));
for (PINDEX k=0; k< OpenMCU::defaultRoomCount; k++) {
PString alias = gkAlias;
alias.Replace("*",k);
AddAliasName(alias); // Add the alias to the endpoint aliaslist
AliasList.AppendString(alias);
}
// Gatekeeper prefixes
PINDEX prefixSize = cfg.GetInteger(PString(GatekeeperPrefixesKey) + " Array Size");
if (prefixSize > 0) {
for (int j = 0; j < prefixSize; j++) {
PString prefix = cfg.GetString(psprintf("%s %u", GatekeeperPrefixesKey, j+1));
PrefixList.AppendString(prefix);
for (PINDEX k=0; k< OpenMCU::defaultRoomCount; k++) {
PString alias = prefix + PString(k);
AliasList.AppendString(alias);
}
}
}
rsrc->Add(new PHTTPFieldArray(new PHTTPStringField(cfg.GetDefaultSection() + "\\" + GatekeeperPrefixesKey,
GatekeeperPrefixesKey, 20, ""), FALSE));
#if OPENMCU_VIDEO
enableVideo = cfg.GetBoolean(EnableVideoKey, TRUE);
rsrc->Add(new PHTTPBooleanField(EnableVideoKey, enableVideo));
videoRate = cfg.GetInteger(VideoFrameRateKey, DefaultVideoFrameRate);
rsrc->Add(new PHTTPIntegerField(VideoFrameRateKey, 1, 30, videoRate));
videoTxQuality = cfg.GetInteger(VideoQualityKey, DefaultVideoQuality);
rsrc->Add(new PHTTPIntegerField(VideoQualityKey, 1, 30, videoTxQuality));
#endif
/*
if (args.GetOptionString('q').IsEmpty()) {
endpoint.behind_masq = FALSE;
} else {
endpoint.masqAddressPtr = new PIPSocket::Address(args.GetOptionString('q'));
endpoint.behind_masq = TRUE;
cout << "Masquerading as address " << *(endpoint.masqAddressPtr) << endl;
} */
capabilities.RemoveAll();
AddAllCapabilities(0, 0, "*");
// disable codecs as required
PString disableCodecs = cfg.GetString(DisableCodecsKey);
rsrc->Add(new PHTTPStringField(DisableCodecsKey, 50, disableCodecs));
if (!disableCodecs.IsEmpty()) {
PStringArray toRemove = disableCodecs.Tokenise(',', FALSE);
capabilities.Remove(toRemove);
}
#if 0 // old MCU options
int videoTxQual = 10;
if (args.HasOption("videotxquality"))
videoTxQual = args.GetOptionString("videotxquality").AsInteger();
endpoint.videoTxQuality = PMAX(1, PMIN(31, videoTxQual));
int videoF = 2;
if (args.HasOption("videofill"))
videoF = args.GetOptionString("videofill").AsInteger();
endpoint.videoFill = PMAX(1, PMIN(99, videoF));
int videoFPS = 10;
if (args.HasOption("videotxfps"))
videoFPS = args.GetOptionString("videotxfps").AsInteger();
endpoint.videoFramesPS = PMAX(1,PMIN(30,videoFPS));
int videoBitRate = 0; //disable setting videoBitRate.
if (args.HasOption("videobitrate")) {
videoBitRate = args.GetOptionString("videobitrate").AsInteger();
videoBitRate = 1024 * PMAX(16, PMIN(2048, videoBitRate));
}
endpoint.videoBitRate = videoBitRate;
#endif
AddAllUserInputCapabilities(0, 2);
switch (gkMode) {
default:
case Gatekeeper_None:
break;
case Gatekeeper_Find:
if (!DiscoverGatekeeper(new H323TransportUDP(*this)))
PSYSTEMLOG(Error, "No gatekeeper found");
else
PSYSTEMLOG(Info, "Found Gatekeeper: " << gatekeeper);
break;
case Gatekeeper_Explicit:
if (!SetGatekeeper(gkName, new H323TransportUDP(*this)))
PSYSTEMLOG(Error, "Error registering with gatekeeper at \"" << gkName << '"');
else
PSYSTEMLOG(Info, "Registered with Gatekeeper: " << gkName);
}
PTRACE(2, "MCU\tCodecs (in preference order):\n" << setprecision(2) << GetCapabilities());;
}
H323Connection * OpenMCUH323EndPoint::CreateConnection(
unsigned callReference,
void * userData,
H323Transport *,
H323SignalPDU *)
{
return new OpenMCUH323Connection(*this, callReference, userData);
}
void OpenMCUH323EndPoint::TranslateTCPAddress(PIPSocket::Address &localAddr, const PIPSocket::Address &remoteAddr)
{
// if (this->behind_masq &&
// (remoteAddr.Byte1() != 192)) {
// localAddr = *(this->masqAddressPtr);
// }
return;
}
PString OpenMCUH323EndPoint::GetRoomStatus(const PString & block)
{
PString substitution;
PWaitAndSignal m(conferenceManager.GetConferenceListMutex());
ConferenceListType & conferenceList = conferenceManager.GetConferenceList();
ConferenceListType::iterator r;
for (r = conferenceList.begin(); r != conferenceList.end(); ++r) {
// make a copy of the repeating html chunk
PString insert = block;
PStringStream members;
members << "<table border=1>"
"<tr>"
"<th>"
" Name "
"</th><th>"
" Duration "
"</th><th>"
" Codec "
"</th><th>"
" RTP Packets/Bytes tx "
"</th><th>"
" RTP Packets/Bytes rx "
"</th>"
#if OPENMCU_VIDEO
"<th>"
" TX Video frame rate/RX Video frame rate "
"</th>"
#endif
"</tr>";
Conference & conference = *(r->second);
size_t memberListSize = 0;
{
PWaitAndSignal m(conference.GetMutex());
Conference::MemberList & memberList = conference.GetMemberList();
memberListSize = memberList.size();
Conference::MemberList::const_iterator s;
for (s = memberList.begin(); s != memberList.end(); ++s) {
ConferenceMember * member = s->second;
H323Connection_ConferenceMember * connMember = dynamic_cast<H323Connection_ConferenceMember *>(member);
if (connMember != NULL) {
OpenMCUH323Connection * conn = (OpenMCUH323Connection *)FindConnectionWithLock(connMember->GetH323Token());
if (conn != NULL) {
PTime now;
PTime callStart = conn->GetConnectionStartTime();
RTP_Session * session = conn->GetSession(RTP_Session::DefaultAudioSessionID);
members << "<tr>"
"<td>"
<< conn->GetRemotePartyName()
<< (member->IsMCU() ? "<BR>(MCU)" : "")
<< "</td><td>"
<< (now -callStart)
<< "</td><td>"
<< conn->GetAudioTransmitCodecName() << '/' << conn->GetAudioReceiveCodecName()
#if OPENMCU_VIDEO
<< "<BR>" << conn->GetVideoTransmitCodecName() << '/' << conn->GetVideoReceiveCodecName()
#endif
<< "</td><td>"
<< session->GetPacketsSent() << '/' << session->GetOctetsSent()
<< "</td><td>"
<< session->GetPacketsReceived() << '/' << session->GetOctetsReceived()
<< "</td>";
conn->Unlock();
}
}
members
#if OPENMCU_VIDEO
<< "<td>"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -