1 /*
2  * Copyright (C) 2002-2003 Fhg Fokus
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * For a license to use the sems software under conditions
12  * other than those described here, or to purchase support for this
13  * software, please contact iptel.org by e-mail at the following addresses:
14  *    info@iptel.org
15  *
16  * SEMS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25 
26 #include "AmConferenceStatus.h"
27 #include "AmConferenceChannel.h"
28 #include "AmMultiPartyMixer.h"
29 #include "AmSessionContainer.h"
30 
31 #include "AmAudio.h"
32 #include "log.h"
33 
34 #include <assert.h>
35 #include <unistd.h>
36 
37 std::map<std::string,AmConferenceStatus*> AmConferenceStatus::cid2status;
38 AmMutex                         AmConferenceStatus::cid2s_mut;
39 
40 //
41 // static methods
42 //
getChannel(const string & cid,const string & local_tag,int input_sample_rate)43 AmConferenceChannel* AmConferenceStatus::getChannel(const string& cid,
44 						    const string& local_tag, int input_sample_rate)
45 {
46   AmConferenceStatus*  st = 0;
47   AmConferenceChannel* ch = 0;
48 
49   cid2s_mut.lock();
50   std::map<std::string,AmConferenceStatus*>::iterator it = cid2status.find(cid);
51 
52   if(it != cid2status.end()){
53 
54     st = it->second;
55   }
56   else {
57 
58     st = new AmConferenceStatus(cid);
59     cid2status[cid] = st;
60   }
61 
62   ch = st->getChannel(local_tag, input_sample_rate);
63   cid2s_mut.unlock();
64 
65   return ch;
66 }
67 
getConferenceSize(const string & cid)68 size_t AmConferenceStatus::getConferenceSize(const string& cid) {
69 
70   cid2s_mut.lock();
71   std::map<std::string,AmConferenceStatus*>::iterator it = cid2status.find(cid);
72 
73   size_t res = 0;
74   if(it != cid2status.end())
75     res = it->second->channels.size();
76 
77   cid2s_mut.unlock();
78 
79   return res;
80 }
81 
postConferenceEvent(const string & cid,int event_id,const string & sess_id)82 void AmConferenceStatus::postConferenceEvent(const string& cid,
83 					     int event_id, const string& sess_id) {
84   AmConferenceStatus*  st = 0;
85 
86   cid2s_mut.lock();
87   std::map<std::string,AmConferenceStatus*>::iterator it = cid2status.find(cid);
88 
89   if(it != cid2status.end()){
90 
91     st = it->second;
92   }
93   else {
94 
95     st = new AmConferenceStatus(cid);
96     cid2status[cid] = st;
97   }
98 
99   st->postConferenceEvent(event_id, sess_id);
100   cid2s_mut.unlock();
101 }
102 
releaseChannel(const string & cid,unsigned int ch_id)103 void AmConferenceStatus::releaseChannel(const string& cid, unsigned int ch_id)
104 {
105   cid2s_mut.lock();
106   std::map<std::string,AmConferenceStatus*>::iterator it = cid2status.find(cid);
107 
108   if(it != cid2status.end()){
109 
110     AmConferenceStatus* st = it->second;
111     if(!st->releaseChannel(ch_id)){
112       cid2status.erase(it);
113       delete st;
114     }
115   }
116   else {
117     ERROR("conference '%s' does not exists\n",cid.c_str());
118   }
119   cid2s_mut.unlock();
120 }
121 
122 //
123 // instance methods
124 //
125 
AmConferenceStatus(const string & conference_id)126 AmConferenceStatus::AmConferenceStatus(const string& conference_id)
127   : conf_id(conference_id), mixer(), sessions(), channels()
128 {
129 }
130 
~AmConferenceStatus()131 AmConferenceStatus::~AmConferenceStatus()
132 {
133   DBG("AmConferenceStatus::~AmConferenceStatus(): conf_id = %s\n",conf_id.c_str());
134 }
135 
postConferenceEvent(int event_id,const string & sess_id)136 void AmConferenceStatus::postConferenceEvent(int event_id, const string& sess_id)
137 {
138   sessions_mut.lock();
139   int participants = sessions.size();
140   for(std::map<std::string, unsigned int>::iterator it = sessions.begin();
141       it != sessions.end(); it++){
142     AmSessionContainer::instance()->postEvent(
143 					      it->first,
144 					      new ConferenceEvent(event_id,
145 								  participants,conf_id,sess_id)
146 					      );
147   }
148   sessions_mut.unlock();
149 }
150 
getChannel(const string & sess_id,int input_sample_rate)151 AmConferenceChannel* AmConferenceStatus::getChannel(const string& sess_id, int input_sample_rate)
152 {
153   AmConferenceChannel* ch = 0;
154 
155   sessions_mut.lock();
156   std::map<std::string, unsigned int>::iterator it = sessions.find(sess_id);
157   if(it != sessions.end()){
158     ch = new AmConferenceChannel(this,it->second,sess_id,false);
159   } else {
160     if(!sessions.empty()){
161       int participants = sessions.size()+1;
162       for(it = sessions.begin(); it != sessions.end(); it++){
163 	AmSessionContainer::instance()->postEvent(
164 						  it->first,
165 						  new ConferenceEvent(ConfNewParticipant,
166 								      participants,conf_id,sess_id)
167 						  );
168       }
169     } else {
170       // The First participant gets its own NewParticipant message
171       AmSessionContainer::instance()->postEvent(
172 						sess_id, new ConferenceEvent(ConfNewParticipant,1,
173 									     conf_id,sess_id));
174     }
175 
176     unsigned int ch_id = mixer.addChannel(input_sample_rate);
177     SessInfo* si = new SessInfo(sess_id,ch_id);
178 
179     sessions[sess_id] = ch_id;
180     channels[ch_id] = si;
181 
182     ch = new AmConferenceChannel(this,ch_id,sess_id, true);
183 
184   }
185   sessions_mut.unlock();
186 
187   return ch;
188 }
189 
releaseChannel(unsigned int ch_id)190 int AmConferenceStatus::releaseChannel(unsigned int ch_id)
191 {
192   unsigned int participants=0;
193 
194   sessions_mut.lock();
195   std::map<unsigned int, SessInfo*>::iterator it = channels.find(ch_id);
196   if(it != channels.end()){
197 
198     SessInfo* si = it->second;
199     channels.erase(it);
200     sessions.erase(si->sess_id);
201 
202     mixer.removeChannel(ch_id);
203 
204     participants = channels.size();
205     std::map<std::string, unsigned int>::iterator s_it;
206     for(s_it = sessions.begin(); s_it != sessions.end(); s_it++){
207 
208       AmSessionContainer::instance()->postEvent(
209 						s_it->first,
210 						new ConferenceEvent(ConfParticipantLeft,
211 								    participants,
212 								    conf_id, si->sess_id));
213     }
214     delete si;
215 
216   }
217   else {
218     participants = channels.size();
219     ERROR("bad channel id=%i within conference status '%s'\n",
220 	  ch_id,conf_id.c_str());
221   }
222   sessions_mut.unlock();
223 
224   return participants;
225 }
226