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