📄 conference.cxx
字号:
/*
* conference.cxx
*
* Conferencing functions 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 this code were written by Post Increment (http://www.postincrement.com)
* with the assistance of funding from Citron Networks (http://www.citron.com.tw)
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): Derek J Smithies (derek@indranet.co.nz)
* ------------------------------
*
* $Log: conference.cxx,v $
* Revision 2.5 2004/09/22 22:39:26 csoutheren
* Fixed race condition, thanks to Neil McCurdy
*
* Revision 2.4 2004/05/26 06:54:31 csoutheren
* Changed to be a PHTTPServiceProcess
* Added ability to play WAV files on member entry and exit
* Added additional documentation on all classes
* Preparation for re-introducing video
*
* Revision 2.3 2004/03/31 03:36:38 csoutheren
* Fixed problem with user indication messages
* Fixed problems with room listener and unlisten
*
* Revision 2.2 2004/03/30 11:27:23 csoutheren
* Reverted to old mixing algorithm
*
* Revision 2.1 2004/03/23 11:40:06 csoutheren
* Fixed problem where deleting map element in-place causes crash at end of call
* Fixed problem where referencing map by iterator rather than ID
* Fixed code formatting problems
*
* Revision 2.0 2004/03/08 02:06:24 csoutheren
* Totally rewritten to use new connection locking mecahnism
* Added ability to monitor conferences
* Added initial support for H.323 MCU messages
* Thanks to Citron Networks for supporting this work
*
*/
#include <ptlib.h>
#include "conference.h"
// size of a PCM data packet, in samples
#define PCM_PACKET_LEN 240
// size of a PCM data buffer, in bytes
#define PCM_BUFFER_LEN (PCM_PACKET_LEN * 2)
// number of PCM buffers to keep
#define PCM_BUFFER_COUNT 2
#define PCM_BUFFER_SIZE (PCM_BUFFER_LEN * PCM_BUFFER_COUNT)
////////////////////////////////////////////////////////////////////////////////////
ConferenceManager::ConferenceManager()
{
}
Conference * ConferenceManager::MakeConference(const PString & roomToCreate, const PString & name)
{
OpalGloballyUniqueID conferenceID;
{
PWaitAndSignal m(conferenceListMutex);
ConferenceList::const_iterator r;
for (r = conferenceList.begin(); r != conferenceList.end(); ++r) {
if (roomToCreate == r->second->GetNumber()) {
conferenceID = r->second->GetID();
break;
}
}
}
return MakeConference(conferenceID, roomToCreate, name);
}
Conference * ConferenceManager::MakeConference(const OpalGloballyUniqueID & conferenceID,
const PString & roomToCreate,
const PString & name)
{
Conference * conference = NULL;
BOOL newConference = FALSE;
{
PWaitAndSignal m(conferenceListMutex);
ConferenceList::const_iterator r = conferenceList.find(conferenceID);
if (r != conferenceList.end())
conference = r->second;
else {
conference = CreateConference(conferenceID, roomToCreate, name);
conferenceList.insert(std::pair<OpalGloballyUniqueID, Conference *>(conferenceID, conference));
newConference = TRUE;
}
}
if (newConference)
OnCreateConference(conference);
return conference;
}
Conference * ConferenceManager::CreateConference(const OpalGloballyUniqueID & _guid,
const PString & _number,
const PString & _name)
{
return new Conference(*this, _guid, _number, _name);
}
BOOL ConferenceManager::HasConference(const OpalGloballyUniqueID & conferenceID)
{
PWaitAndSignal m(conferenceListMutex);
ConferenceList::const_iterator r = conferenceList.find(conferenceID);
return r != conferenceList.end();
}
BOOL ConferenceManager::HasConference(const PString & number)
{
PWaitAndSignal m(conferenceListMutex);
ConferenceList::const_iterator r;
for (r = conferenceList.begin(); r != conferenceList.end(); ++r) {
if (r->second->GetNumber() == number)
return TRUE;
}
return FALSE;
}
void ConferenceManager::RemoveConference(const OpalGloballyUniqueID & confId)
{
PWaitAndSignal m(conferenceListMutex);
ConferenceList::iterator r = conferenceList.find(confId);
if (r != conferenceList.end()) {
Conference * conf = r->second;
OnDestroyConference(conf);
conferenceList.erase(confId);
delete conf;
}
}
void ConferenceManager::RemoveMember(const OpalGloballyUniqueID & confId, ConferenceMember * toRemove)
{
Conference * conf = toRemove->GetConference();
BOOL removeConf = conf->RemoveMember(toRemove);
delete toRemove;
if (removeConf)
RemoveConference(conf->GetID());
}
////////////////////////////////////////////////////////////////////////////////////
Conference::Conference( ConferenceManager & _manager,
const OpalGloballyUniqueID & _guid,
const PString & _number,
const PString & _name)
: manager(_manager), guid(_guid), number(_number), name(_name)
{
//memberList.DisallowDeleteObjects();
PTRACE(3, "Conference\tNew conference started: ID=" << guid << ", number = " << number);
#ifndef NO_MCU_VIDEO
// if this is the first connection to a room, create the video buffer.
if (create_new_room) {
//cout << "CREATING VIDEO BUFFER FOR "<<newRoomID<<endl;
videoBufferDict.SetAt(newRoomID, new VideoBuffer);
VideoBuffer & videoBuffer = videoBufferDict[newRoomID];
if (videoLarge)
videoBuffer.SetSize(352,288);
// create the spoken list.
spokenListDict.SetAt(newRoomID, new PStringList);
if (singleStream) {
PStringList & spokenList = spokenListDict[newRoomID];
spokenList.AppendString(newToken);
}
// create the position list.
videoPosnDict.SetAt(newRoomID, new PStringList);
PStringList & videoPosnList = videoPosnDict[newRoomID];
if (singleStream) {
videoPosnList.AppendString("");
} else {
PINDEX i;
for(i=0;i<4;i++) // hard coded to support 4 images
videoPosnList.AppendString("");
}
}
// Normally we display the video for the "active" users, ie
// people who are currently speaking (based on noise detection)
//
// If there are currently less than 4 members then we can display
// the video right from the start, before they begin talking.
// This is also handy for connections with video, but no audio.
//
// Problem is finding out whether or not an ep sends video.
// That is for a coming version.
if (singleStream) {
//only first connection must send video
if (create_new_room) {
AddVideoPosnToken(newToken,newRoomID);
}
} else {
AddVideoPosnToken(newToken,newRoomID);
}
#endif
}
Conference::~Conference()
{
}
void Conference::AddMember(ConferenceMember * memberToAdd)
{
PTRACE(3, "Conference\tAdding member " << memberToAdd->GetName() << " to conference " << guid);
cout << memberToAdd->GetName() << " joining conference " << number << "(" << guid << ")" << endl;
// add the member to the conference
memberToAdd->AddToConference(this);
{
// lock the member list
PWaitAndSignal m(memberListMutex);
// add this member to the conference member list
memberList.insert(std::pair<void *, ConferenceMember *>(memberToAdd->GetID(), memberToAdd));
// make sure each member has a connection created for the new member
// make sure the new member has a connection created for reach existing member
std::map<void *, ConferenceMember *>::const_iterator r;
for (r = memberList.begin(); r != memberList.end(); r++) {
ConferenceMember * conn = r->second;
if (conn != memberToAdd) {
conn->AddConnection(memberToAdd);
memberToAdd->AddConnection(conn);
}
}
}
// call the callback function
OnMemberJoining(memberToAdd);
}
BOOL Conference::RemoveMember(ConferenceMember * memberToRemove)
{
PTRACE(3, "Conference\tRemoving call " << memberToRemove->GetName() << " from conference " << guid << " with size " << (PINDEX)memberList.size());
cout << memberToRemove->GetName() << " leaving conference " << number << "(" << guid << ")" << endl;
BOOL result;
{
PWaitAndSignal m(memberListMutex);
// remove this member from the connection lists for all other members
std::map<void *, ConferenceMember *>::iterator r;
for (r = memberList.begin(); r != memberList.end(); r++) {
ConferenceMember * conn = r->second;
if (conn != memberToRemove)
r->second->RemoveConnection(memberToRemove->GetID());
}
// remove this connection from the member list
memberList.erase(memberToRemove->GetID());
// return TRUE if conference is empty
result = memberList.size() == 0;
}
// call the callback function
if (!result)
OnMemberLeaving(memberToRemove);
return result;
}
#ifndef NO_MCU_VIDEO
PINDEX Conference::FindTokensVideoPosn(const PString & thisToken,
const PString & roomID)
{
PStringList & videoPosnList = videoPosnDict[roomID];
PINDEX keyIndex;
for (keyIndex = 0; keyIndex<videoPosnList.GetSize(); keyIndex++)
if (thisToken == videoPosnList[keyIndex] )
return keyIndex;
return P_MAX_INDEX;
}
BOOL Conference::AddVideoPosnToken(const PString & thisToken,
const PString & roomID)
{
PStringList & videoPosnList = videoPosnDict[roomID];
PINDEX keyIndex;
for (keyIndex = 0; keyIndex<videoPosnList.GetSize(); keyIndex++)
if (videoPosnList[keyIndex] == "" ) {
videoPosnList[keyIndex] = thisToken;
return TRUE;
}
return FALSE;
}
#endif
#if 0
BOOL Conference::WriteAudio(OpenMCUH323Connection * source, const void * buffer, PINDEX amount)
{
//The spokenList construct is required to determine who were the last
//to speak, which is needed for determining which four videoimages are displayed.
//spokenList contains a sorted list of when the last packet was received from
//which connection. Thus, when an audio packet is received from a connection,
//the name of the connection is moved to the end of the list.
// If someone new comes along, everyone moves down.
#ifndef NO_MCU_VIDEO
if ( DetectNoise(buffer,amount) && !singleStream ) {
PStringList & spokenList = spokenListDict[roomID];
PINDEX keyIndex = spokenList.GetStringsIndex(thisToken);
if (keyIndex != P_MAX_INDEX)
spokenList.RemoveAt(keyIndex);
spokenList.AppendString(thisToken);
if (FindTokensVideoPosn(thisToken,roomID) != P_MAX_INDEX)
goto processAudio;
if (!singleStream && AddVideoPosnToken(thisToken,roomID))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -