/*
* Copyright 2007 Sun Microsystems, Inc.
*
* This file is part of jVoiceBridge.
*
* jVoiceBridge is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation and distributed hereunder
* to you.
*
* jVoiceBridge is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied this
* code.
*/
package com.sun.voip.server;
import com.sun.voip.CallParticipant;
import com.sun.voip.ConferenceEvent;
import com.sun.voip.DistributedBridge;
import com.sun.voip.Logger;
import com.sun.voip.MediaInfo;
import com.sun.voip.RtpPacket;
import com.sun.voip.SdpManager;
import com.sun.voip.TreatmentManager;
import java.io.IOException;
import java.text.ParseException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.NoSuchElementException;
import java.util.ArrayList;
import org.ifsoft.rayo.RayoComponent;
/**
* Manage a conference consisting of members.
* Each conference has a unique String identifying it.
* Members can join and leave the conference.
*/
public class ConferenceManager {
private static ArrayList conferenceList = new ArrayList();
private String conferenceId; // conference identifier
private String displayName; // user readable name
private String callId; // target call id
private ArrayList memberList; // for iterating members
private boolean isFirstMember = true;
private boolean privateCall = false;
private boolean transferCall = false;
private CallParticipant heldCall = null;
private String groupName = null;
/*
* If useSingleSender is true, a single
* conferenceSender will be used for all conferences.
*/
private static boolean useSingleSender = true;
private static ConferenceSender loneConferenceSender;
private static int loneReceiverPort = 0;
private static ConferenceReceiver loneConferenceReceiver;
private ConferenceSender conferenceSender; // sender thread
private WGManager wgManager; // whisper group manager
private ConferenceReceiver conferenceReceiver; // receiver thread
private boolean permanent = false;
private static int totalMembers = 0;
private String mediaPreference; // new media preference
private MediaInfo mediaInfo;
private long conferenceStartTime;
private static DistributedBridge distributedBridge;
private boolean done = false;
static {
String s = System.getProperty("com.sun.voip.server.LONE_RECEIVER_PORT");
if (s != null && s.length() > 0) {
try {
loneReceiverPort = Integer.parseInt(s);
} catch (NumberFormatException e) {
Logger.println("Invalid port for lone receiver: " + s);
}
}
}
/**
* Constructor
*
* Create a new conference
* @param conferenceId String identifying the conference
*/
private ConferenceManager(String conferenceId, String mediaPreference,
String displayName) throws SocketException {
this.conferenceId = conferenceId;
memberList = new ArrayList();
try {
setMediaInfo(mediaPreference);
} catch (ParseException e) {
Logger.println(conferenceId
+ ": Can't set meeting media setting to "
+ mediaPreference + ": " + e.getMessage());
}
this.displayName = displayName;
if (useSingleSender == true) {
if (loneConferenceSender == null) {
loneConferenceSender = new ConferenceSender(conferenceList);
}
conferenceSender = loneConferenceSender;
} else {
conferenceSender = new ConferenceSender(this);
}
if (loneReceiverPort != 0) {
if (loneConferenceReceiver == null) {
loneConferenceReceiver =
new ConferenceReceiver("Singleton", loneReceiverPort); // start receiver
}
conferenceReceiver = loneConferenceReceiver;
} else {
conferenceReceiver = new ConferenceReceiver(conferenceId, 0); // start receiver
}
}
public void setMediaInfo(String mediaPreference) throws ParseException {
/*
* Conference id may be qualified by the media parameters.
* The syntax is <conferenceId>:<PCM[U]|SPEEX/<sampleRate>/<channels>
*/
mediaInfo = parseMediaPreference(mediaPreference);
mediaPreference = null;
if (wgManager == null) {
/*
* Use the conference Id as the name of the main conference
* whisper group.
*/
wgManager = new WGManager(conferenceId, mediaInfo);
} else {
wgManager.setMediaInfo(mediaInfo);
}
}
private MediaInfo parseMediaPreference(String mediaPreference)
throws ParseException {
if (mediaPreference == null) {
if (mediaInfo != null) {
return mediaInfo;
}
return SdpManager.findMediaInfo(RtpPacket.PCMU_ENCODING, 8000, 1);
}
int ix;
int encoding = RtpPacket.PCMU_ENCODING;
int sampleRate = 8000;
int channels = 1;
try {
if (mediaPreference.indexOf("PCMU/") == 0) {
encoding = RtpPacket.PCMU_ENCODING;
mediaPreference = mediaPreference.substring(5);
} else if (mediaPreference.indexOf("PCM/") == 0) {
encoding = RtpPacket.PCM_ENCODING;
mediaPreference = mediaPreference.substring(4);
} else if (mediaPreference.indexOf("SPEEX/") == 0) {
encoding = RtpPacket.SPEEX_ENCODING;
mediaPreference = mediaPreference.substring(6);
} else if (mediaPreference.indexOf("PCM") == 0) {
// do nothing
} else {
Logger.println("Invalid media specification " + mediaPreference);
}
if ((ix = mediaPreference.indexOf("/")) < 0) {
Logger.println("Invalid media specification " + mediaPreference);
} else {
sampleRate = Integer.parseInt(mediaPreference.substring(0, ix));
channels = Integer.parseInt(mediaPreference.substring(ix + 1));
}
} catch (IndexOutOfBoundsException e) {
Logger.println("Invalid media specification " + mediaPreference);
} catch (NumberFormatException e) {
Logger.println("Invalid media specification " + mediaPreference);
}
if (sampleRate == 8000 && channels == 1 &&
encoding == RtpPacket.PCM_ENCODING) {
encoding = RtpPacket.PCMU_ENCODING;
}
MediaInfo mediaInfo =
SdpManager.findMediaInfo(encoding, sampleRate, channels);
Logger.println("conference " + conferenceId
+ " using media settings " + mediaInfo);
conferenceStartTime = System.currentTimeMillis();
return mediaInfo;
}
public long getConferenceStartTime() {
return conferenceStartTime;
}
public WGManager getWGManager() {
return wgManager;
}
public static WhisperGroup createWhisperGroup(String conferenceId,
String whisperGroupId, double attenuation) throws ParseException {
synchronized (conferenceList) {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
return conferenceManager.createWhisperGroup(whisperGroupId,
attenuation);
}
}
public WhisperGroup createWhisperGroup(String whisperGroupId,
double attenuation) throws ParseException {
synchronized (conferenceList) {
return wgManager.createWhisperGroup(whisperGroupId, attenuation);
}
}
public static void destroyWhisperGroup(String conferenceId,
String whisperGroupId) throws ParseException {
synchronized (conferenceList) {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
conferenceManager.destroyWhisperGroup(whisperGroupId);
}
}
public void destroyWhisperGroup(String whisperGroupId)
throws ParseException {
synchronized (conferenceList) {
synchronized (this) {
wgManager.destroyWhisperGroup(whisperGroupId);
}
}
}
public static String getAbbreviatedWhisperGroupInfo(boolean showMembers) {
String s = "";
synchronized (conferenceList) {
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager = (ConferenceManager)
conferenceList.get(i);
s += "Whisper groups for conference "
+ conferenceManager.getId() + "\n";
s += conferenceManager.getWGManager().getAbbreviatedWhisperGroupInfo(true);
s += "\n";
}
}
return s;
}
public static String getWhisperGroupInfo() {
String s = "";
synchronized (conferenceList) {
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager = (ConferenceManager)
conferenceList.get(i);
s += "Whisper groups for conference "
+ conferenceManager.getId() + "\n";
s += conferenceManager.getWGManager().getWhisperGroupInfo();
s += "\n";
}
}
return s;
}
public static void setTransientWhisperGroup(String conferenceId,
String whisperGroupId, boolean isTransient) throws ParseException {
synchronized (conferenceList) {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
conferenceManager.getWGManager().setTransientWhisperGroup(
whisperGroupId, isTransient);
}
}
public static void setLockedWhisperGroup(String conferenceId,
String whisperGroupId, boolean isLocked) throws ParseException {
synchronized (conferenceList) {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
conferenceManager.getWGManager().setLockedWhisperGroup(
whisperGroupId, isLocked);
}
}
public static void setWhisperGroupAttenuation(String conferenceId,
String whisperGroupId, double attenuation) throws ParseException {
synchronized (conferenceList) {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
conferenceManager.getWGManager().setWhisperGroupAttenuation(
whisperGroupId, attenuation);
}
}
public static void setWhisperGroupNoCommonMix(String conferenceId,
String whisperGroupId, boolean noCommonMix) throws ParseException {
synchronized (conferenceList) {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
synchronized (conferenceManager) {
WGManager wgManager = conferenceManager.getWGManager();
synchronized (wgManager.getWhisperGroups()) {
wgManager.setWhisperGroupNoCommonMix(whisperGroupId,
noCommonMix);
ArrayList memberList = conferenceManager.getMemberList();
synchronized (memberList) {
for (int i = 0; i < memberList.size(); i++) {
ConferenceMember member = (ConferenceMember)
memberList.get(i);
/*
* Tell members
*/
if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("Call " + member
+ " no common mix");
}
member.setNoCommonMix(whisperGroupId);
}
}
}
}
}
}
private void end() {
try {
recordConference(false, null, null);
} catch (ParseException e) {
Logger.println(conferenceId
+ ": Failed to stop recording conference! "
+ e.getMessage());
}
Logger.writeFile("ending conf " + conferenceId
+ ": permanent " + permanent
+ ", mediaPreference " + mediaPreference);
if (permanent) {
conferenceSender.printStatistics();
if (mediaPreference != null) {
try {
setMediaInfo(mediaPreference);
} catch (ParseException e) {
Logger.println(conferenceId
+ ": Can't change meeting media setting to "
+ mediaPreference + ": " + e.getMessage());
}
mediaPreference = null;
}
} else {
if (done) {
return;
}
done = true;
ConferenceManager.conferenceEventNotification(new ConferenceEvent(ConferenceEvent.CONFERENCE_ENDED, conferenceId));
synchronized(conferenceList) {
conferenceList.remove(this);
}
if (conferenceReceiver != loneConferenceReceiver) {
conferenceReceiver.end();
}
conferenceSender.printStatistics();
}
int activeConferences = 0;
synchronized(conferenceList) {
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager =
(ConferenceManager) conferenceList.get(i);
if (conferenceManager.getMemberList().size() > 0) {
activeConferences++;
}
}
}
Logger.println("");
Logger.println("Conference: '" + conferenceId + "' has ended. "
+ "conferences still in progress: " + activeConferences);
Logger.println("");
Logger.flush();
if (totalMembers == 0) {
/*
* This is a great time to do a full garbage collection
*/
Logger.println("No conferences in progress, doing a full GC...");
System.gc();
}
}
public static void setDistributedBridge(DistributedBridge distributedBridge) {
ConferenceManager.distributedBridge = distributedBridge;
}
private static void conferenceEventNotification(ConferenceEvent event)
{
if (distributedBridge != null)
{
try {
distributedBridge.conferenceEventNotification(event);
} catch (Exception e) {
Logger.println("conferenceEventNotification exception: " + e.getMessage());
e.printStackTrace();
}
}
RayoComponent.self.notifyConferenceMonitors(event);
}
public static int getNumberOfConferences() {
return conferenceList.size();
}
public static int getTotalMembers() {
return totalMembers;
}
public static int getNumberOfMembers(String conferenceId)
throws ParseException {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
return conferenceManager.getNumberOfMembers();
}
public int getNumberOfMembers() {
if (distributedBridge != null) {
return distributedBridge.getNumberOfMembers(conferenceId);
}
return getMemberList().size();
}
/**
* Get the conference identifier.
*
* @return conferenceId String identifying this conference
*/
public String getId() {
return conferenceId;
}
public String getCallId() {
return callId;
}
public void setCallId(String callId) {
this.callId = callId;
}
public static String getCallId(String conferenceId)
{
try {
ConferenceManager conferenceManager = findConferenceManager(conferenceId);
return conferenceManager.getCallId();
} catch (ParseException e) {
return null;
}
}
public static void setCallId(String conferenceId, String callId)
{
try {
ConferenceManager conferenceManager = findConferenceManager(conferenceId);
conferenceManager.setCallId(callId);
} catch (ParseException e) {
}
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public static String getDisplayName(String conferenceId)
{
try {
ConferenceManager conferenceManager = findConferenceManager(conferenceId);
return conferenceManager.getDisplayName();
} catch (ParseException e) {
return null;
}
}
public static void setDisplayName(String conferenceId, String displayName)
{
try {
ConferenceManager conferenceManager = findConferenceManager(conferenceId);
conferenceManager.setDisplayName(displayName);
} catch (ParseException e) {
}
}
public void setPermanent(boolean permanent) {
this.permanent = permanent;
}
public boolean isPermanent() {
return permanent;
}
/**
* Get the conferenceSender for this conference.
*
* @return conferenceSender ConferenceSender for this conference
*/
public ConferenceSender getConferenceSender() {
return conferenceSender;
}
public ConferenceReceiver getConferenceReceiver() {
return conferenceReceiver;
}
private void endConferenceSender() {
synchronized (this) {
if (conferenceSender != loneConferenceSender) {
conferenceSender.end();
}
if (conferenceReceiver != loneConferenceReceiver) {
conferenceReceiver.end();
}
}
}
public void setMediaPreference(String mediaPreference) {
this.mediaPreference = mediaPreference;
permanent = true;
}
/**
* Get the memberList for this conference.
*
* @return memberList ArrayList of members for this conference.
*/
public ArrayList getMemberList() {
return memberList;
}
/**
* Is this the first member. The first member to call this gets true.
* Others get false. This is so that the first member can get a special
* audio treatment.
* @return true if this is the first member, false otherwise
*/
public boolean isFirstMember()
{
synchronized (memberList) {
if (isFirstMember == false) {
return false;
}
isFirstMember = false;
return memberList.isEmpty();
}
}
public boolean isTransferCall()
{
return transferCall;
}
public static boolean isTransferCall(String conferenceId)
{
try {
ConferenceManager conferenceManager = findConferenceManager(conferenceId);
return conferenceManager.isTransferCall();
} catch (ParseException e) {
return false;
}
}
public void setTransferCall(boolean transferCall)
{
this.transferCall = transferCall;
}
public boolean isPrivateCall()
{
return privateCall;
}
public void setPrivateCall(boolean privateCall)
{
this.privateCall = privateCall;
}
public CallParticipant getHeldCall()
{
return heldCall;
}
public static CallParticipant getHeldCall(String conferenceId)
{
try {
ConferenceManager conferenceManager = findConferenceManager(conferenceId);
return conferenceManager.getHeldCall();
} catch (ParseException e) {
return null;
}
}
public void setHeldCall(CallParticipant heldCall)
{
this.heldCall = heldCall;
}
public static void setHeldCall(String conferenceId, CallParticipant heldCall)
{
try {
ConferenceManager conferenceManager = findConferenceManager(conferenceId);
conferenceManager.setHeldCall(heldCall);
} catch (ParseException e) {
}
}
public String getGroupName()
{
return groupName;
}
public void setGroupName(String groupName)
{
this.groupName = groupName;
}
/**
* Add a new member to the conference
*
* @param cp CallParticipant wishing to join the conference.
* @return ConferenceMember
*/
public ConferenceMember joinConference(CallParticipant cp)
throws IOException {
if (conferenceJoinTreatment != null) {
cp.setConferenceJoinTreatment(conferenceJoinTreatment);
}
if (conferenceLeaveTreatment != null) {
cp.setConferenceLeaveTreatment(conferenceLeaveTreatment);
}
if (conferenceAnswerTreatment != null) {
cp.setCallEstablishedTreatment(conferenceAnswerTreatment);
cp.setCallAnsweredTreatment(null);
cp.setJoinConfirmationTimeout(0);
}
if (displayName != null) {
//cp.setDisplayName(displayName);
cp.setConferenceDisplayName(displayName);
}
ConferenceMember member = new ConferenceMember(this, cp);
joinConference(member);
return member;
}
private void joinConference(ConferenceMember member) throws IOException {
synchronized (memberList) {
memberList.add(member);
totalMembers++;
String s = "";
conferenceReceiver.addMember(member);
Logger.println("conferenceManager: '" + conferenceId + "',"
+ " new member " + member + s
+ " total members: " + memberList.size());
}
ConferenceEvent event = new ConferenceEvent(ConferenceEvent.MEMBER_JOINED, conferenceId);
event.setCallId(member.getCallParticipant().getCallId());
event.setMemberAddress(member.getMemberSender().getSendAddress());
event.setMemberCount(memberList.size());
conferenceEventNotification(event);
}
public static boolean hasCommonMix(String conferenceId) {
synchronized(conferenceList) {
try {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
return conferenceManager.hasCommonMix();
} catch (ParseException e) {
Logger.println(e.getMessage());
}
return false;
}
}
public boolean hasCommonMix() {
return wgManager.hasCommonMix();
}
public void joinDistributedConference(ConferenceMember member) {
ConferenceEvent event = new ConferenceEvent(
ConferenceEvent.MEMBER_JOINED, conferenceId);
event.setCallId(member.getCallParticipant().getCallId());
event.setMemberAddress(
member.getMemberSender().getSendAddress());
event.setIsDistributedBridge(
member.getCallParticipant().isDistributedBridge());
conferenceEventNotification(event);
}
/*
* Transfer an incoming call to the target conference.
*/
public void transferMember(ConferenceManager newConferenceManager, ConferenceMember member) throws IOException
{
leave(member, true); // leave the temporary conference
member.reinitialize(newConferenceManager, true);
newConferenceManager.joinConference(member); // join the new conference
}
/**
* Remove a member from a conference
* @param member ConferenceMember leaving the conference
*/
public void leave(ConferenceMember member) {
leave(member, false);
}
/*
* keepMember is set to true when a member transfers
* from one conference to another.
* This is used for incoming calls which require a temporary conference
* until the caller specified the desired conference to enter.
*/
public void leave(ConferenceMember member, boolean keepMember) {
conferenceReceiver.removeMember(member);
synchronized (this) {
synchronized (memberList) {
memberList.remove(member);
totalMembers--;
if (keepMember == false) {
member.end();
}
Logger.println("conferenceManager: '" + conferenceId
+ "': member " + member.toString()
+ " leaving, remaining: " + memberList.size());
}
if (member.joinedDistributedConference())
{
ConferenceEvent event = new ConferenceEvent(ConferenceEvent.MEMBER_LEFT, conferenceId);
event.setCallId(member.getCallParticipant().getCallId());
event.setMemberAddress(member.getMemberSender().getSendAddress());
event.setIsDistributedBridge(member.getCallParticipant().isDistributedBridge());
ConferenceManager.conferenceEventNotification(event);
}
ConferenceEvent event = new ConferenceEvent(ConferenceEvent.MEMBER_LEFT, conferenceId);
event.setCallId(member.getCallParticipant().getCallId());
event.setMemberAddress(member.getMemberSender().getSendAddress());
event.setMemberCount(memberList.size());
ConferenceManager.conferenceEventNotification(event);
boolean endOfDistributedConference = true;
synchronized (memberList) {
for (int i = 0; i < memberList.size(); i++) {
ConferenceMember m = (ConferenceMember) memberList.get(i);
if (m.getCallParticipant().isDistributedBridge() == false) {
endOfDistributedConference = false;
break;
}
}
}
if (endOfDistributedConference) {
endAllCalls();
}
if (memberList.size() == 0) {
end(); // last member left, the conference is over
}
}
}
private void endAllCalls() {
synchronized (memberList) {
for (int i = 0; i < memberList.size(); i++) {
ConferenceMember member = (ConferenceMember)
memberList.get(i);
member.cancelRequest("End of Distributed Conference");
}
}
}
/**
* Get the ArrayList identifying all conferences.
* @return ArrayList list of Conferences
*/
public static ArrayList getConferenceList() {
return conferenceList;
}
public static void useSingleSender(boolean useSingleSender) {
if (ConferenceManager.useSingleSender == useSingleSender) {
return;
}
if (useSingleSender == true) {
ConferenceManager.useSingleSender = true;
loneConferenceSender = new ConferenceSender(conferenceList);
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager =
(ConferenceManager) conferenceList.get(i);
synchronized (conferenceManager) {
conferenceManager.endConferenceSender();
conferenceManager.setNewConferenceSender(
loneConferenceSender);
}
}
} else {
synchronized (conferenceList) {
ConferenceManager.useSingleSender = false;
if (loneConferenceSender != null) {
loneConferenceSender.end();
loneConferenceSender = null;
}
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager =
(ConferenceManager) conferenceList.get(i);
conferenceManager.setNewConferenceSender();
}
}
}
}
public static void setLoneReceiverPort(int loneReceiverPort)
throws ParseException {
if (ConferenceManager.loneReceiverPort == loneReceiverPort) {
return;
}
if (totalMembers != 0) {
Logger.println(
"Can't change loneReceiverPort while conferences are in progress");
throw new ParseException(
"Can't change loneReceiverPort while conferences are in progress", 0);
}
ConferenceManager.loneReceiverPort = loneReceiverPort;
}
private void setNewConferenceSender(ConferenceSender conferenceSender) {
synchronized (this) {
this.conferenceSender = conferenceSender;
}
}
private void setNewConferenceSender() {
synchronized (this) {
conferenceSender = new ConferenceSender(this);
}
}
public static boolean useSingleSender() {
return useSingleSender;
}
public static int loneReceiverPort() {
return loneReceiverPort;
}
/**
* Create a new conference with the specified media settings
*/
public static void createConference(String conferenceId,
String mediaPreference, String displayName) throws ParseException {
synchronized(conferenceList) {
ConferenceManager conferenceManager = getConference(conferenceId, mediaPreference, displayName, true);
if (conferenceManager.getMemberList().size() == 0) {
if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("Conference " + conferenceId
+ " setting media preference to "
+ mediaPreference);
}
conferenceManager.setPermanent(true);
try {
conferenceManager.setMediaInfo(mediaPreference);
} catch (ParseException e) {
try {
removeConference(conferenceId);
} catch (ParseException ee) {
}
Logger.println(conferenceId
+ ": Can't change meeting media setting to "
+ mediaPreference + ": " + e.getMessage());
throw new ParseException(conferenceId
+ ": Can't change meeting media setting to "
+ mediaPreference + ": " + e.getMessage(), 0);
}
} else {
/*
* Defer until conference ends
*/
if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("Conference " + conferenceId
+ " defer setting media preference to "
+ mediaPreference);
}
conferenceManager.setMediaPreference(mediaPreference);
}
}
}
public static void removeConference(String conferenceId)
throws ParseException {
synchronized(conferenceList) {
ConferenceManager conferenceManager =
findConferenceManager(conferenceId);
if (conferenceManager.getMemberList().size() > 0) {
throw new ParseException("can't remove conference: '"
+ conferenceId
+ "' because there are still calls in progress", 0);
}
conferenceManager.setPermanent(false);
conferenceManager.end();
}
}
/*
* End a conference
*/
public static void endConference(String conferenceId)
throws ParseException {
ConferenceManager conferenceManager;
synchronized (conferenceList) {
conferenceManager = findConferenceManager(conferenceId);
ArrayList memberList = conferenceManager.getMemberList();
synchronized (memberList) {
for (int i = 0; i < memberList.size(); i++) {
ConferenceMember member = (ConferenceMember) memberList.get(i);
CallHandler callHandler = member.getCallHandler();
callHandler.cancelRequest("Conference forced to end");
}
conferenceManager.end();
}
}
}
private static boolean allowShortNames = true;
public static void setAllowShortNames(boolean allowShortNames) {
ConferenceManager.allowShortNames = allowShortNames;
}
public static boolean allowShortNames() {
return allowShortNames;
}
public static ConferenceManager findConferenceManager(
String conferenceId) throws ParseException {
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager = (ConferenceManager)
conferenceList.get(i);
if (conferenceManager.getId().equals(conferenceId)) {
return conferenceManager;
}
if (allowShortNames == true) {
String displayName = conferenceManager.getDisplayName();
if (displayName != null && displayName.equals(conferenceId)) {
return conferenceManager;
}
}
}
throw new ParseException("Non-existent conference "
+ conferenceId, 0);
}
/**
* Start a new conference or return existing Conference with the
* specified id
* @param conferenceId String identifier of conference
* @return ConferenceManager
*/
public static ConferenceManager getConference(String conferenceId) {
return getConference(conferenceId, null, null, false);
}
public static ConferenceManager getConference(CallParticipant cp) {
return getConference(cp.getConferenceId(), cp.getMediaPreference(),
cp.getConferenceDisplayName(), false);
}
public static ConferenceManager getConference(String conferenceId,
String mediaPreference, String displayName) {
return getConference(conferenceId, mediaPreference, displayName,
false);
}
public static ConferenceManager getConference(String conferenceId,
String mediaPreference, String displayName, boolean permanent) {
ConferenceManager conferenceManager;
try {
conferenceManager = findConferenceManager(conferenceId);
if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("found existing conference: '"
+ conferenceId + "'");
}
return conferenceManager;
} catch (ParseException e) {
}
try {
conferenceManager =
new ConferenceManager(conferenceId, mediaPreference,
displayName);
} catch (SocketException e) {
Logger.error("Can't create conference " + conferenceId
+ " " + e.getMessage());
return null;
}
synchronized(conferenceList) {
conferenceList.add(conferenceManager);
}
Logger.println("starting new conference: '"
+ conferenceId + "'. "
+ " conferences in progress: " + conferenceList.size());
conferenceManager.setPermanent(permanent);
String id = conferenceManager.getId();
if (displayName != null) {
id += ":" + mediaPreference + ":" + displayName;
}
ConferenceManager.conferenceEventNotification(new ConferenceEvent(ConferenceEvent.CONFERENCE_STARTED, id));
return conferenceManager;
}
public MediaInfo getMediaInfo() {
return mediaInfo;
}
public static void dropDb() {
if (distributedBridge != null) {
distributedBridge.dropDb();
} else {
Logger.println(
"The Distributed Conference Manager is not installed");
}
}
public static String getDistributedConferenceInfo() {
if (distributedBridge != null) {
return distributedBridge.getDistributedConferenceInfo();
}
Logger.println("The Distributed Bridge Manager is not installed");
return "The Distributed Conference Manager is not installed";
}
/**
* Display information about each conference
* @param requestHandler RequestHandler with socket to write output to
*/
public static String getBriefConferenceInfo() {
return getConferenceInfo(0);
}
public static String getAbbreviatedConferenceInfo() {
return getConferenceInfo(1);
}
public static String getDetailedConferenceInfo() {
return getConferenceInfo(2);
}
private static String getConferenceInfo(int format) {
synchronized(conferenceList) {
if (conferenceList.size() == 0) {
if (format != 0) {
return ("\n\n\n\n");
}
return "";
}
String s = "";
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager = (ConferenceManager)
conferenceList.get(i);
String id = conferenceManager.getId();
String displayName = conferenceManager.getDisplayName();
if (format != 1) {
if (displayName != null) {
id += " '" + displayName + "'";
}
} else {
if (displayName == null) {
if (id.length() >= 14) {
id = id.substring(0, 13);
}
} else {
id = "'" + displayName + "'";
}
}
s += "Conference Id: " + id + " ";
s += conferenceManager.getMediaInfo().toString();
s += " Members=" + conferenceManager.getMemberList().size();
if (conferenceManager.isPermanent()) {
s += " persistent";
}
String recordingFile =
conferenceManager.getWGManager().getRecordingFile();
if (recordingFile != null) {
s += " Recording to " + recordingFile;
}
s += "\n";
if (format == 0) {
continue;
}
/*
* Copy the member list so we can avoid unnecessary
* synchronization
*/
ArrayList memberList = (ArrayList)
conferenceManager.getMemberList().clone();
for (int n = 0; n < memberList.size(); n++) {
ConferenceMember member = (ConferenceMember)
memberList.get(n);
MemberSender memberSender = member.getMemberSender();
MemberReceiver memberReceiver = member.getMemberReceiver();
String info = " ";
MediaInfo transmitMediaInfo = memberSender.getMediaInfo();
if (transmitMediaInfo != null) {
info += transmitMediaInfo.toString();
}
MediaInfo receiveMediaInfo = memberReceiver.getMediaInfo();
if (receiveMediaInfo != null) {
if (transmitMediaInfo.getEncoding() !=
receiveMediaInfo.getEncoding() ||
transmitMediaInfo.getSampleRate() !=
receiveMediaInfo.getSampleRate() ||
transmitMediaInfo.getChannels() !=
receiveMediaInfo.getChannels()) {
/*
* The member is transmitting at a different
* media setting than it is receiving.
*/
info += " Transmit:"
+ memberReceiver.getMediaInfo();
}
}
CallParticipant cp = member.getCallParticipant();
if (cp.isMuted()) {
info += " MUTED";
}
if (cp.isConferenceMuted()) {
info += " CONFERENCE_MUTED";
}
if (cp.isConferenceSilenced()) {
info += " MAIN_CONFERENCE_SILENCED";
}
if (memberReceiver.doNotRecord() == true) {
info += " RECORDED NOT ALLOWED";
}
if (memberReceiver.getFromRecordingFile() != null) {
info += " Recording from member in "
+ memberReceiver.getFromRecordingFile();
}
if (cp.isRecorder()) {
String toRecordingFile =
memberSender.getCallParticipant().getToRecordingFile();
if (toRecordingFile != null) {
info += " Recording to member in " + toRecordingFile;
} else {
info += " Recorder";
}
}
if (cp.speexEncode()) {
info += " SpeexEncode";
}
//
// For debugging
//
if (memberSender.getSendAddress() != null) {
String gateway = "";
String address =
memberSender.getSendAddress().toString();
int ix = address.indexOf("/");
if (ix >= 0) {
address = address.substring(ix + 1);
if ((ix = address.indexOf(":")) >= 0) {
address = address.substring(0, ix);
}
}
if (address.equals("10.6.4.192")) {
gateway = " Menlo Park Gateway";
} else if (address.equals("129.148.75.22")) {
gateway = " Burlington Gateway";
} else if (address.equals("10.1.224.22")) {
gateway = " Broomfield Gateway";
}
info += gateway;
}
if (format == 2) {
info += conferenceManager.getWGManager().getWhisperGroupInfo(member);
}
cp = member.getCallParticipant();
id = cp.toString();
if (format == 1) {
id = cp.toConsiseString();
}
s += " " + id + info + "\n";
}
s += "\n";
}
return s + "\n";
}
}
/**
* Record a specified conference
*/
public static void recordConference(String conferenceId, boolean enabled,
String recordingFile, String recordingType) throws ParseException {
synchronized(conferenceList) {
ConferenceManager conferenceManager;
if ((conferenceManager = findConferenceManager(conferenceId)) !=
null) {
conferenceManager.recordConference(enabled, recordingFile,
recordingType);
return;
}
throw new ParseException("No such conference " + conferenceId, 0);
}
}
public void recordConference(boolean enabled, String recordingFile,
String recordingType) throws ParseException {
if (wgManager == null) {
return;
}
try {
wgManager.recordConference(enabled, recordingFile, recordingType);
} catch (IOException e) {
throw new ParseException(e.getMessage(), 0);
}
}
public static void setConferenceJoinTreatment(String conferenceId,
String treatment) throws ParseException {
synchronized(conferenceList) {
ConferenceManager conferenceManager;
conferenceManager = findConferenceManager(conferenceId);
conferenceManager.setConferenceJoinTreatment(treatment);
}
}
private String conferenceJoinTreatment;
public void setConferenceJoinTreatment(String treatment) {
conferenceJoinTreatment = treatment;
}
private String conferenceLeaveTreatment;
public static void setConferenceLeaveTreatment(String conferenceId,
String treatment) throws ParseException {
synchronized(conferenceList) {
ConferenceManager conferenceManager;
conferenceManager = findConferenceManager(conferenceId);
conferenceManager.setConferenceLeaveTreatment(treatment);
}
}
public void setConferenceLeaveTreatment(String treatment) {
conferenceLeaveTreatment = treatment;
}
private String conferenceAnswerTreatment;
public static void setConferenceAnswerTreatment(String conferenceId,
String treatment) throws ParseException {
synchronized(conferenceList) {
ConferenceManager conferenceManager;
conferenceManager = findConferenceManager(conferenceId);
conferenceManager.setConferenceAnswerTreatment(treatment);
}
}
public void setConferenceAnswerTreatment(String treatment) {
if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("Setting conference answer treatment to " + treatment);
}
conferenceAnswerTreatment = treatment;
}
public String getConferenceAnswerTreatment() {
return conferenceAnswerTreatment;
}
public static void playTreatmentToAllConferences(String treatment,
double[] volume) throws ParseException {
}
public static void playTreatmentToAllConferences(String treatment)
throws ParseException {
synchronized(conferenceList) {
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager =
(ConferenceManager) conferenceList.get(i);
playTreatment(conferenceManager.getId(), treatment);
}
}
}
public static void playTreatment(String conferenceId,
String treatment, double[] volume) throws ParseException {
}
/**
* Play a treatment to the specified conference
*/
public static void playTreatment(String conferenceId,
String treatment) throws ParseException {
if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println("playing treatment " + treatment + " to "
+ conferenceId);
}
synchronized(conferenceList) {
ConferenceManager conferenceManager;
conferenceManager = findConferenceManager(conferenceId);
try {
conferenceManager.addTreatment(treatment);
} catch (IOException e) {
throw new ParseException("bad treatment "
+ " " + e.getMessage(), 0);
}
return;
}
}
public void addTreatment(String treatment) throws IOException {
if (!done) {
synchronized (this) {
if (wgManager.hasCommonMix()) {
wgManager.addConferenceTreatment(new TreatmentManager(
treatment, 0, mediaInfo.getSampleRate(),
mediaInfo.getChannels()));
} else {
synchronized (memberList) {
for (int i = 0; i < memberList.size(); i++) {
ConferenceMember member = (ConferenceMember)
memberList.get(i);
member.addTreatment(new TreatmentManager(
treatment, 0, mediaInfo.getSampleRate(),
mediaInfo.getChannels()));
}
}
}
}
}
}
public static void pauseTreatment(String conferenceId, String treatment,
boolean isPaused) throws ParseException {
if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println("pausing treatment " + treatment + " to "
+ conferenceId);
}
synchronized(conferenceList) {
ConferenceManager conferenceManager;
conferenceManager = findConferenceManager(conferenceId);
conferenceManager.getWGManager().pauseConferenceTreatment(
treatment, isPaused);
}
}
public static void stopTreatment(String conferenceId, String treatment)
throws ParseException {
if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println("stopping treatment " + treatment + " to "
+ conferenceId);
}
synchronized(conferenceList) {
ConferenceManager conferenceManager;
conferenceManager = findConferenceManager(conferenceId);
conferenceManager.getWGManager().removeConferenceTreatment(
treatment);
}
}
/**
* get conference statistics
*/
public static void printStatistics() {
synchronized(conferenceList) {
if (loneConferenceSender != null) {
loneConferenceSender.printStatistics();
}
for (int i = 0; i < conferenceList.size(); i++) {
ConferenceManager conferenceManager =
(ConferenceManager) conferenceList.get(i);
ConferenceSender conferenceSender =
conferenceManager.getConferenceSender();
if (loneConferenceSender == null) {
conferenceSender.printStatistics();
}
ArrayList memberList = conferenceManager.getMemberList();
for (int n = 0; n < memberList.size(); n++) {
ConferenceMember member = (ConferenceMember)
memberList.get(n);
member.printStatistics();
}
}
}
Logger.flush();
}
}