git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@371 8eb893ce-cfd4-0310-b710-fb5ebe64c474
0 | 10 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,78 @@ |
1 |
+webconference : conference with dial-in and dial-out over DI (xmlrpc) |
|
2 |
+ |
|
3 |
+This conference module can do dial-in, dial-out and mixed |
|
4 |
+dial-in/dial-out conferences. It can be controlled over DI functions |
|
5 |
+from other modules, and, for example, using the xmlrpc2di module, |
|
6 |
+the conference rooms can be controlled via XMLRPC. |
|
7 |
+ |
|
8 |
+It implements conference rooms with dial-in and conference room entry |
|
9 |
+via DTMF, and authenticated dial-out. |
|
10 |
+ |
|
11 |
+Participants can be listed, kicked out, muted and unmuted over DI |
|
12 |
+(using xmlrpc2di over XMLRPC). |
|
13 |
+ |
|
14 |
+implemented DI functions: |
|
15 |
+ |
|
16 |
+---- |
|
17 |
+roomCreate(string room): |
|
18 |
+ int code, string result, string adminpin |
|
19 |
+ |
|
20 |
+ code/result: |
|
21 |
+ 0 OK |
|
22 |
+ 1 room already open |
|
23 |
+---- |
|
24 |
+roomInfo(string room, string adminpin): |
|
25 |
+ int code, string result, list<participant> participants |
|
26 |
+ participant: string call_tag, string number, int status, string reason, int muted |
|
27 |
+ |
|
28 |
+ status: |
|
29 |
+ 0 Disconnected |
|
30 |
+ 1 Connecting |
|
31 |
+ 2 Ringing |
|
32 |
+ 3 Connected |
|
33 |
+ 4 Disconnecting |
|
34 |
+ reason: e.g. "200 OK", "606 Declined", ... |
|
35 |
+ |
|
36 |
+ code/result: |
|
37 |
+ 0 OK |
|
38 |
+ 1 wrong adminpin |
|
39 |
+---- |
|
40 |
+dialout(string room, string adminpin, string callee, |
|
41 |
+ string from_user, string domain, |
|
42 |
+ string auth_user, string auth_realm, string auth_pwd) : |
|
43 |
+ int code, string result, string callid |
|
44 |
+ |
|
45 |
+ code/result: |
|
46 |
+ 0 OK |
|
47 |
+ 1 wrong adminpin |
|
48 |
+ 2 failed |
|
49 |
+---- |
|
50 |
+kickout(string room, string adminpin, string call_tag) : |
|
51 |
+ int code, string result |
|
52 |
+ |
|
53 |
+ code/result: |
|
54 |
+ 0 OK |
|
55 |
+ 1 wrong adminpin |
|
56 |
+ 2 call does not exist in room |
|
57 |
+---- |
|
58 |
+mute(string room, string adminpin, string call_tag) : |
|
59 |
+ int code, string result |
|
60 |
+ |
|
61 |
+ code/result: |
|
62 |
+ 0 OK |
|
63 |
+ 1 wrong adminpin |
|
64 |
+ 2 call does not exist in room |
|
65 |
+---- |
|
66 |
+unmute(string room, string adminpin, string call_tag) : |
|
67 |
+ int code, string result |
|
68 |
+ |
|
69 |
+ code/result: |
|
70 |
+ 0 OK |
|
71 |
+ 1 wrong adminpin |
|
72 |
+ 2 call does not exist in room |
|
73 |
+---- |
|
74 |
+serverInfo(): |
|
75 |
+ string name, |
|
76 |
+ int load, |
|
77 |
+ int cpu |
|
78 |
+---- |
|
0 | 79 |
\ No newline at end of file |
1 | 80 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,114 @@ |
1 |
+ |
|
2 |
+#include "RoomInfo.h" |
|
3 |
+#include <string.h> |
|
4 |
+#include "log.h" |
|
5 |
+ |
|
6 |
+void ConferenceRoomParticipant::updateAccess(const struct timeval& now) { |
|
7 |
+ memcpy(&last_access_time, &now, sizeof(struct timeval)); |
|
8 |
+} |
|
9 |
+ |
|
10 |
+bool ConferenceRoomParticipant::expired(const struct timeval& now) { |
|
11 |
+ if (Finished != status) |
|
12 |
+ return false; |
|
13 |
+ |
|
14 |
+ struct timeval diff; |
|
15 |
+ timersub(&now,&last_access_time,&diff); |
|
16 |
+ return (diff.tv_sec > 0) && |
|
17 |
+ (unsigned int)diff.tv_sec > PARTICIPANT_EXPIRED_DELAY; |
|
18 |
+} |
|
19 |
+ |
|
20 |
+AmArgArray* ConferenceRoomParticipant::asArgArray() { |
|
21 |
+ AmArgArray* res = new AmArgArray(); |
|
22 |
+ res->push(AmArg(localtag.c_str())); |
|
23 |
+ res->push(AmArg(number.c_str())); |
|
24 |
+ res->push(AmArg((int)status)); |
|
25 |
+ res->push(AmArg(last_reason.c_str())); |
|
26 |
+ res->push(AmArg((int)muted)); |
|
27 |
+ return res; |
|
28 |
+} |
|
29 |
+ |
|
30 |
+void ConferenceRoomParticipant::setMuted(int mute) { |
|
31 |
+ muted = mute; |
|
32 |
+} |
|
33 |
+ |
|
34 |
+void ConferenceRoomParticipant::updateStatus(ConferenceRoomParticipant::ParticipantStatus |
|
35 |
+ new_status, |
|
36 |
+ const string& reason) { |
|
37 |
+ status = new_status; |
|
38 |
+ last_reason = reason; |
|
39 |
+ struct timeval now; |
|
40 |
+ gettimeofday(&now, NULL); |
|
41 |
+ updateAccess(now); |
|
42 |
+} |
|
43 |
+ |
|
44 |
+void ConferenceRoom::cleanExpired() { |
|
45 |
+ struct timeval now; |
|
46 |
+ gettimeofday(&now, NULL); |
|
47 |
+ |
|
48 |
+ list<ConferenceRoomParticipant>::iterator it=participants.begin(); |
|
49 |
+ while (it != participants.end()) { |
|
50 |
+ if (it->expired(now)) { |
|
51 |
+ participants.erase(it); |
|
52 |
+ it=participants.begin(); |
|
53 |
+ } else |
|
54 |
+ it++; |
|
55 |
+ } |
|
56 |
+} |
|
57 |
+ |
|
58 |
+AmArgArray* ConferenceRoom::asArgArray() { |
|
59 |
+ cleanExpired(); |
|
60 |
+ AmArgArray* res = new AmArgArray(); |
|
61 |
+ for (list<ConferenceRoomParticipant>::iterator it=participants.begin(); |
|
62 |
+ it != participants.end(); it++) { |
|
63 |
+ AmArg r; |
|
64 |
+ r.setBorrowedPointer(it->asArgArray()); |
|
65 |
+ res->push(r); |
|
66 |
+ } |
|
67 |
+ return res; |
|
68 |
+} |
|
69 |
+ |
|
70 |
+void ConferenceRoom::newParticipant(const string& localtag, |
|
71 |
+ const string& number) { |
|
72 |
+ participants.push_back(ConferenceRoomParticipant()); |
|
73 |
+ participants.back().localtag = localtag; |
|
74 |
+ participants.back().number = number; |
|
75 |
+} |
|
76 |
+ |
|
77 |
+bool ConferenceRoom::hasParticipant(const string& localtag) { |
|
78 |
+ bool res = false; |
|
79 |
+ |
|
80 |
+ for (list<ConferenceRoomParticipant>::iterator it =participants.begin(); |
|
81 |
+ it != participants.end();it++) |
|
82 |
+ if (it->localtag == localtag) { |
|
83 |
+ res = true; |
|
84 |
+ break; |
|
85 |
+ } |
|
86 |
+ return res; |
|
87 |
+} |
|
88 |
+ |
|
89 |
+void ConferenceRoom::setMuted(const string& localtag, int mute) { |
|
90 |
+ for (list<ConferenceRoomParticipant>::iterator it =participants.begin(); |
|
91 |
+ it != participants.end();it++) |
|
92 |
+ if (it->localtag == localtag) { |
|
93 |
+ it->setMuted(mute); |
|
94 |
+ break; |
|
95 |
+ } |
|
96 |
+} |
|
97 |
+ |
|
98 |
+bool ConferenceRoom::updateStatus(const string& part_tag, |
|
99 |
+ ConferenceRoomParticipant::ParticipantStatus newstatus, |
|
100 |
+ const string& reason) { |
|
101 |
+ cleanExpired(); |
|
102 |
+ |
|
103 |
+ bool res = false; |
|
104 |
+ list<ConferenceRoomParticipant>::iterator it=participants.begin(); |
|
105 |
+ while (it != participants.end()) { |
|
106 |
+ if (it->localtag == part_tag) { |
|
107 |
+ it->updateStatus(newstatus, reason); |
|
108 |
+ res = true; |
|
109 |
+ } |
|
110 |
+ it++; |
|
111 |
+ } |
|
112 |
+ return res; |
|
113 |
+} |
|
114 |
+ |
0 | 115 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,78 @@ |
1 |
+ |
|
2 |
+#ifndef ROOM_INFO_H |
|
3 |
+#define ROOM_INFO_H |
|
4 |
+ |
|
5 |
+#include <string> |
|
6 |
+using std::string; |
|
7 |
+ |
|
8 |
+#include <list> |
|
9 |
+using std::list; |
|
10 |
+ |
|
11 |
+#include <sys/time.h> |
|
12 |
+ |
|
13 |
+ |
|
14 |
+#include "AmArg.h" |
|
15 |
+#include "AmThread.h" |
|
16 |
+ |
|
17 |
+#define PARTICIPANT_EXPIRED_DELAY 10 |
|
18 |
+ |
|
19 |
+struct ConferenceRoomParticipant { |
|
20 |
+ enum ParticipantStatus { |
|
21 |
+ Disconnected = 0, |
|
22 |
+ Connecting, |
|
23 |
+ Ringing, |
|
24 |
+ Connected, |
|
25 |
+ Disconnecting, |
|
26 |
+ Finished |
|
27 |
+ }; |
|
28 |
+ |
|
29 |
+ string localtag; |
|
30 |
+ string number; |
|
31 |
+ ParticipantStatus status; |
|
32 |
+ string last_reason; |
|
33 |
+ |
|
34 |
+ int muted; |
|
35 |
+ |
|
36 |
+ struct timeval last_access_time; |
|
37 |
+ |
|
38 |
+ ConferenceRoomParticipant() |
|
39 |
+ : status(Disconnected), muted(0) { } |
|
40 |
+ |
|
41 |
+ ~ConferenceRoomParticipant() { } |
|
42 |
+ |
|
43 |
+ inline void updateAccess(const struct timeval& now); |
|
44 |
+ inline bool expired(const struct timeval& now); |
|
45 |
+ |
|
46 |
+ inline void updateStatus(ParticipantStatus new_status, |
|
47 |
+ const string& reason); |
|
48 |
+ |
|
49 |
+ inline void setMuted(int mute); |
|
50 |
+ |
|
51 |
+ AmArgArray* asArgArray(); |
|
52 |
+}; |
|
53 |
+ |
|
54 |
+struct ConferenceRoom { |
|
55 |
+ string adminpin; |
|
56 |
+ |
|
57 |
+ list<ConferenceRoomParticipant> participants; |
|
58 |
+ |
|
59 |
+ ConferenceRoom() { } |
|
60 |
+ ~ConferenceRoom() { } |
|
61 |
+ |
|
62 |
+ void cleanExpired(); |
|
63 |
+ |
|
64 |
+ AmArgArray* asArgArray(); |
|
65 |
+ |
|
66 |
+ void newParticipant(const string& localtag, const string& number); |
|
67 |
+ |
|
68 |
+ bool updateStatus(const string& part_tag, |
|
69 |
+ ConferenceRoomParticipant::ParticipantStatus newstatus, |
|
70 |
+ const string& reason); |
|
71 |
+ |
|
72 |
+ bool hasParticipant(const string& localtag); |
|
73 |
+ |
|
74 |
+ void setMuted(const string& localtag, int mute); |
|
75 |
+}; |
|
76 |
+ |
|
77 |
+ |
|
78 |
+#endif |
0 | 79 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,627 @@ |
1 |
+/* |
|
2 |
+ * $Id: WebConference.cpp 288 2007-03-28 16:32:02Z sayer $ |
|
3 |
+ * |
|
4 |
+ * Copyright (C) 2007 iptego GmbH |
|
5 |
+ * |
|
6 |
+ * This file is part of sems, a free SIP media server. |
|
7 |
+ * |
|
8 |
+ * sems is free software; you can redistribute it and/or modify |
|
9 |
+ * it under the terms of the GNU General Public License as published by |
|
10 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
11 |
+ * (at your option) any later version. |
|
12 |
+ * |
|
13 |
+ * For a license to use the sems software under conditions |
|
14 |
+ * other than those described here, or to purchase support for this |
|
15 |
+ * software, please contact iptel.org by e-mail at the following addresses: |
|
16 |
+ * info@iptel.org |
|
17 |
+ * |
|
18 |
+ * sems is distributed in the hope that it will be useful, |
|
19 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
20 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
21 |
+ * GNU General Public License for more details. |
|
22 |
+ * |
|
23 |
+ * You should have received a copy of the GNU General Public License |
|
24 |
+ * along with this program; if not, write to the Free Software |
|
25 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
26 |
+ */ |
|
27 |
+ |
|
28 |
+#include "WebConference.h" |
|
29 |
+#include "AmConferenceStatus.h" |
|
30 |
+#include "AmUtils.h" |
|
31 |
+#include "log.h" |
|
32 |
+#include "AmUAC.h" |
|
33 |
+#include "AmPlugIn.h" |
|
34 |
+#include "AmSessionContainer.h" |
|
35 |
+ |
|
36 |
+#include <stdlib.h> |
|
37 |
+ |
|
38 |
+#define APP_NAME "webconference" |
|
39 |
+ |
|
40 |
+EXPORT_SESSION_FACTORY(WebConferenceFactory,APP_NAME); |
|
41 |
+EXPORT_PLUGIN_CLASS_FACTORY(WebConferenceFactory,APP_NAME); |
|
42 |
+ |
|
43 |
+WebConferenceFactory::WebConferenceFactory(const string& _app_name) |
|
44 |
+ : AmSessionFactory(_app_name), |
|
45 |
+ AmDynInvokeFactory(_app_name), |
|
46 |
+ configured(false) |
|
47 |
+{ |
|
48 |
+ if (NULL == _instance) { |
|
49 |
+ _instance = this; |
|
50 |
+ } |
|
51 |
+} |
|
52 |
+ |
|
53 |
+WebConferenceFactory* WebConferenceFactory::_instance=0; |
|
54 |
+ |
|
55 |
+string WebConferenceFactory::DigitsDir; |
|
56 |
+PlayoutType WebConferenceFactory::m_PlayoutType = ADAPTIVE_PLAYOUT; |
|
57 |
+ |
|
58 |
+int WebConferenceFactory::onLoad() |
|
59 |
+{ |
|
60 |
+ // only execute this once |
|
61 |
+ if (configured) |
|
62 |
+ return 0; |
|
63 |
+ configured = true; |
|
64 |
+ |
|
65 |
+ AmConfigReader cfg; |
|
66 |
+ if(cfg.loadFile(AmConfig::ModConfigPath + string(APP_NAME)+ ".conf")) |
|
67 |
+ return -1; |
|
68 |
+ |
|
69 |
+ // get application specific global parameters |
|
70 |
+ configureModule(cfg); |
|
71 |
+ |
|
72 |
+ // get prompts |
|
73 |
+ AM_PROMPT_START; |
|
74 |
+ AM_PROMPT_ADD(FIRST_PARTICIPANT, ANNOUNCE_PATH "first_paricipant.wav"); |
|
75 |
+ AM_PROMPT_ADD(JOIN_SOUND, ANNOUNCE_PATH "beep.wav"); |
|
76 |
+ AM_PROMPT_ADD(DROP_SOUND, ANNOUNCE_PATH "beep.wav"); |
|
77 |
+ AM_PROMPT_ADD(ENTER_PIN, ANNOUNCE_PATH "enter_pin.wav"); |
|
78 |
+ AM_PROMPT_ADD(WRONG_PIN, ANNOUNCE_PATH "wrong_pin.wav"); |
|
79 |
+ AM_PROMPT_ADD(ENTERING_CONFERENCE, ANNOUNCE_PATH "entering_conference.wav"); |
|
80 |
+ AM_PROMPT_END(prompts, cfg, APP_NAME); |
|
81 |
+ |
|
82 |
+ DigitsDir = cfg.getParameter("digits_dir"); |
|
83 |
+ if (DigitsDir.length() && DigitsDir[DigitsDir.length()-1]!='/') |
|
84 |
+ DigitsDir+='/'; |
|
85 |
+ |
|
86 |
+ if (!DigitsDir.length()) { |
|
87 |
+ WARN("No digits_dir specified in configuration.\n"); |
|
88 |
+ } |
|
89 |
+ for (int i=0;i<10;i++) |
|
90 |
+ prompts.setPrompt(int2str(i), DigitsDir+int2str(i)+".wav", APP_NAME); |
|
91 |
+ |
|
92 |
+ string playout_type = cfg.getParameter("playout_type"); |
|
93 |
+ if (playout_type == "simple") { |
|
94 |
+ m_PlayoutType = SIMPLE_PLAYOUT; |
|
95 |
+ DBG("Using simple (fifo) buffer as playout technique.\n"); |
|
96 |
+ } else if (playout_type == "adaptive_jb") { |
|
97 |
+ m_PlayoutType = JB_PLAYOUT; |
|
98 |
+ DBG("Using adaptive jitter buffer as playout technique.\n"); |
|
99 |
+ } else { |
|
100 |
+ DBG("Using adaptive playout buffer as playout technique.\n"); |
|
101 |
+ } |
|
102 |
+ |
|
103 |
+ return 0; |
|
104 |
+} |
|
105 |
+ |
|
106 |
+void WebConferenceFactory::newParticipant(const string& conf_id, |
|
107 |
+ const string& localtag, |
|
108 |
+ const string& number) { |
|
109 |
+ DBG("newparticipant ------------------- %s %s %s\n", conf_id.c_str(), |
|
110 |
+ localtag.c_str(), |
|
111 |
+ number.c_str()); |
|
112 |
+ rooms_mut.lock(); |
|
113 |
+ rooms[conf_id].newParticipant(localtag, number); |
|
114 |
+ rooms_mut.unlock(); |
|
115 |
+} |
|
116 |
+ |
|
117 |
+void WebConferenceFactory::updateStatus(const string& conf_id, |
|
118 |
+ const string& localtag, |
|
119 |
+ ConferenceRoomParticipant::ParticipantStatus status, |
|
120 |
+ const string& reason) { |
|
121 |
+ rooms_mut.lock(); |
|
122 |
+ rooms[conf_id].updateStatus(localtag, status, reason); |
|
123 |
+ rooms_mut.unlock(); |
|
124 |
+} |
|
125 |
+ |
|
126 |
+ConferenceRoom* WebConferenceFactory::getRoom(const string& room, |
|
127 |
+ const string& adminpin) { |
|
128 |
+ ConferenceRoom* res = NULL; |
|
129 |
+ map<string, ConferenceRoom>::iterator it = rooms.find(room); |
|
130 |
+ if (it == rooms.end()) { |
|
131 |
+ // (re)open room |
|
132 |
+ rooms[room] = ConferenceRoom(); |
|
133 |
+ rooms[room].adminpin = adminpin; |
|
134 |
+ res = &rooms[room]; |
|
135 |
+ } else { |
|
136 |
+ if (!it->second.adminpin.empty() && |
|
137 |
+ (it->second.adminpin != adminpin)) { |
|
138 |
+ // wrong pin |
|
139 |
+ } else { |
|
140 |
+ // update adminpin if room was created by dialin |
|
141 |
+ if (it->second.adminpin.empty()) |
|
142 |
+ it->second.adminpin = adminpin; |
|
143 |
+ res = &it->second; |
|
144 |
+ } |
|
145 |
+ } |
|
146 |
+ |
|
147 |
+ return res; |
|
148 |
+} |
|
149 |
+ |
|
150 |
+// incoming calls |
|
151 |
+AmSession* WebConferenceFactory::onInvite(const AmSipRequest& req) |
|
152 |
+{ |
|
153 |
+ DBG("ONINVITE ----------------- INCOMING ---------------------\n"); |
|
154 |
+ return new WebConferenceDialog(prompts, getInstance(), NULL); |
|
155 |
+} |
|
156 |
+ |
|
157 |
+// outgoing calls - req is INVITE |
|
158 |
+AmSession* WebConferenceFactory::onInvite(const AmSipRequest& req, |
|
159 |
+ AmArg& session_params) |
|
160 |
+{ |
|
161 |
+ DBG("ONINVITE ----------------- OUTGOING ---------------------\n"); |
|
162 |
+ |
|
163 |
+ UACAuthCred* cred = NULL; |
|
164 |
+ if (session_params.getType() == AmArg::AObject) { |
|
165 |
+ ArgObject* cred_obj = session_params.asObject(); |
|
166 |
+ if (cred_obj) |
|
167 |
+ cred = dynamic_cast<UACAuthCred*>(cred_obj); |
|
168 |
+ } |
|
169 |
+ |
|
170 |
+ AmSession* s = new WebConferenceDialog(prompts, getInstance(), cred); |
|
171 |
+ |
|
172 |
+ AmSessionEventHandlerFactory* uac_auth_f = |
|
173 |
+ AmPlugIn::instance()->getFactory4Seh("uac_auth"); |
|
174 |
+ if (uac_auth_f != NULL) { |
|
175 |
+ DBG("UAC Auth enabled for new announcement session.\n"); |
|
176 |
+ AmSessionEventHandler* h = uac_auth_f->getHandler(s); |
|
177 |
+ if (h != NULL ) |
|
178 |
+ s->addHandler(h); |
|
179 |
+ } else { |
|
180 |
+ ERROR("uac_auth interface not accessible. Load uac_auth for authenticated dialout.\n"); |
|
181 |
+ } |
|
182 |
+ |
|
183 |
+ return s; |
|
184 |
+} |
|
185 |
+ |
|
186 |
+void WebConferenceFactory::invoke(const string& method, |
|
187 |
+ const AmArgArray& args, |
|
188 |
+ AmArgArray& ret) |
|
189 |
+{ |
|
190 |
+ if(method == "roomCreate"){ |
|
191 |
+ roomCreate(args, ret); |
|
192 |
+ } else if(method == "roomInfo"){ |
|
193 |
+ roomInfo(args, ret); |
|
194 |
+ } else if(method == "dialout"){ |
|
195 |
+ dialout(args, ret); |
|
196 |
+ } else if(method == "mute"){ |
|
197 |
+ mute(args, ret); |
|
198 |
+ } else if(method == "unmute"){ |
|
199 |
+ unmute(args, ret); |
|
200 |
+ } else if(method == "kickout"){ |
|
201 |
+ kickout(args, ret); |
|
202 |
+ } else if(method == "serverInfo"){ |
|
203 |
+ serverInfo(args, ret); |
|
204 |
+ } else if(method == "help"){ |
|
205 |
+ ret.push("help text goes here"); |
|
206 |
+ } else |
|
207 |
+ throw AmDynInvoke::NotImplemented(method); |
|
208 |
+} |
|
209 |
+ |
|
210 |
+string WebConferenceFactory::getRandomPin() { |
|
211 |
+ string res; |
|
212 |
+ for (int i=0;i<6;i++) |
|
213 |
+ res+=(char)('0'+random()%10); |
|
214 |
+ return res; |
|
215 |
+} |
|
216 |
+ |
|
217 |
+void WebConferenceFactory::roomCreate(const AmArgArray& args, AmArgArray& ret) { |
|
218 |
+ string room = args.get(0).asCStr(); |
|
219 |
+ rooms_mut.lock(); |
|
220 |
+ map<string, ConferenceRoom>::iterator it = rooms.find(room); |
|
221 |
+ if (it == rooms.end()) { |
|
222 |
+ rooms[room] = ConferenceRoom(); |
|
223 |
+ rooms[room].adminpin = getRandomPin(); |
|
224 |
+ ret.push(0); |
|
225 |
+ ret.push("OK"); |
|
226 |
+ ret.push(rooms[room].adminpin.c_str()); |
|
227 |
+ } else { |
|
228 |
+ ret.push(1); |
|
229 |
+ ret.push("room already opened"); |
|
230 |
+ } |
|
231 |
+ rooms_mut.unlock(); |
|
232 |
+} |
|
233 |
+ |
|
234 |
+void WebConferenceFactory::roomInfo(const AmArgArray& args, AmArgArray& ret) { |
|
235 |
+ string room = args.get(0).asCStr(); |
|
236 |
+ string adminpin = args.get(1).asCStr();; |
|
237 |
+ |
|
238 |
+ rooms_mut.lock(); |
|
239 |
+ ConferenceRoom* r = getRoom(room, adminpin); |
|
240 |
+ if (NULL == r) { |
|
241 |
+ ret.push(1); |
|
242 |
+ ret.push("wrong adminpin"); |
|
243 |
+ // for consistency, add an empty array |
|
244 |
+ AmArgArray* a = new AmArgArray(); |
|
245 |
+ AmArg res; |
|
246 |
+ res.setBorrowedPointer(a); |
|
247 |
+ ret.push(res); |
|
248 |
+ } else { |
|
249 |
+ ret.push(0); |
|
250 |
+ ret.push("OK"); |
|
251 |
+ AmArg res; |
|
252 |
+ res.setBorrowedPointer(r->asArgArray()); |
|
253 |
+ ret.push(res); |
|
254 |
+ } |
|
255 |
+ rooms_mut.unlock(); |
|
256 |
+ |
|
257 |
+// if (checkAdminpin(room, adminpin)) { |
|
258 |
+// ret.push(0); |
|
259 |
+// ret.push("OK"); |
|
260 |
+// AmArg r; |
|
261 |
+// r.setBorrowedPointer(it->second.asArgArray()); |
|
262 |
+// ret.push(r); |
|
263 |
+// } else { |
|
264 |
+// ret.push(1); |
|
265 |
+// ret.push("wrong adminpin"); |
|
266 |
+// // for consistency, add an empty array |
|
267 |
+// AmArgArray* a = new AmArgArray(); |
|
268 |
+// AmArg r; |
|
269 |
+// r.setBorrowedPointer(a); |
|
270 |
+// ret.push(r); |
|
271 |
+// } |
|
272 |
+ |
|
273 |
+// rooms_mut.lock(); |
|
274 |
+// map<string, ConferenceRoom>::iterator it = rooms.find(room); |
|
275 |
+// if (it == rooms.end()) { |
|
276 |
+// // (re)open room |
|
277 |
+// rooms[room] = ConferenceRoom(); |
|
278 |
+// rooms[room].adminpin = adminpin; |
|
279 |
+// ret.push(0); |
|
280 |
+// ret.push("OK"); |
|
281 |
+// // add empty paricipants list |
|
282 |
+// AmArgArray* a = new AmArgArray(); |
|
283 |
+// AmArg r; |
|
284 |
+// r.setBorrowedPointer(a); |
|
285 |
+// ret.push(r); |
|
286 |
+// } else { |
|
287 |
+// if (!it->second.adminpin.empty() && |
|
288 |
+// (it->second.adminpin != adminpin)) { |
|
289 |
+// ret.push(1); |
|
290 |
+// ret.push("wrong adminpin"); |
|
291 |
+// } else { |
|
292 |
+// // update adminpin if room was created by dialin |
|
293 |
+// if (it->second.adminpin.empty()) |
|
294 |
+// it->second.adminpin = adminpin; |
|
295 |
+// // return room info |
|
296 |
+// ret.push(0); |
|
297 |
+// ret.push("OK"); |
|
298 |
+// AmArg r; |
|
299 |
+// r.setBorrowedPointer(it->second.asArgArray()); |
|
300 |
+// ret.push(r); |
|
301 |
+// } |
|
302 |
+// } |
|
303 |
+ |
|
304 |
+// rooms_mut.unlock(); |
|
305 |
+} |
|
306 |
+ |
|
307 |
+void WebConferenceFactory::dialout(const AmArgArray& args, AmArgArray& ret) { |
|
308 |
+ string room = args.get(0).asCStr(); |
|
309 |
+ string adminpin = args.get(1).asCStr(); |
|
310 |
+ string callee = args.get(2).asCStr(); |
|
311 |
+ string from_user = args.get(3).asCStr(); |
|
312 |
+ string domain = args.get(4).asCStr(); |
|
313 |
+ string auth_user = args.get(5).asCStr(); |
|
314 |
+ string auth_realm = args.get(6).asCStr(); |
|
315 |
+ string auth_pwd = args.get(7).asCStr(); |
|
316 |
+ |
|
317 |
+ string from = "sip:" + from_user + "@" + domain; |
|
318 |
+ string to = "sip:" + callee + "@" + domain; |
|
319 |
+ |
|
320 |
+ // check adminpin |
|
321 |
+ rooms_mut.lock(); |
|
322 |
+ ConferenceRoom* r = getRoom(room, adminpin); |
|
323 |
+ rooms_mut.unlock(); |
|
324 |
+ if (NULL == r) { |
|
325 |
+ ret.push(1); |
|
326 |
+ ret.push("wrong adminpin"); |
|
327 |
+ ret.push(""); |
|
328 |
+ return; |
|
329 |
+ } |
|
330 |
+ |
|
331 |
+ DBG("dialout webconference room '%s', from '%s', to '%s'", |
|
332 |
+ room.c_str(), from.c_str(), to.c_str()); |
|
333 |
+ |
|
334 |
+ AmArg* a = new AmArg(); |
|
335 |
+ a->setBorrowedPointer(new UACAuthCred(auth_realm, auth_user, auth_pwd)); |
|
336 |
+ |
|
337 |
+ AmSession* s = AmUAC::dialout(room.c_str(), APP_NAME, to, |
|
338 |
+ "<" + from + ">", from, "<" + to + ">", |
|
339 |
+ string(""), // callid |
|
340 |
+ a); |
|
341 |
+ if (s) { |
|
342 |
+ string localtag = s->getLocalTag(); |
|
343 |
+ ret.push(0); |
|
344 |
+ ret.push("OK"); |
|
345 |
+ ret.push(localtag.c_str()); |
|
346 |
+ newParticipant(room, localtag, to); |
|
347 |
+ updateStatus(room, localtag, |
|
348 |
+ ConferenceRoomParticipant::Connecting, |
|
349 |
+ "INVITE"); |
|
350 |
+ } |
|
351 |
+ else { |
|
352 |
+ ret.push(1); |
|
353 |
+ ret.push("internal error"); |
|
354 |
+ ret.push(""); |
|
355 |
+ } |
|
356 |
+} |
|
357 |
+ |
|
358 |
+void WebConferenceFactory::postConfEvent(const AmArgArray& args, AmArgArray& ret, |
|
359 |
+ int id, int mute) { |
|
360 |
+ string room = args.get(0).asCStr(); |
|
361 |
+ string adminpin = args.get(1).asCStr(); |
|
362 |
+ string call_tag = args.get(2).asCStr(); |
|
363 |
+ |
|
364 |
+ // check adminpin |
|
365 |
+ |
|
366 |
+ rooms_mut.lock(); |
|
367 |
+ ConferenceRoom* r = getRoom(room, adminpin); |
|
368 |
+ if (NULL == r) { |
|
369 |
+ ret.push(1); |
|
370 |
+ ret.push("wrong adminpin"); |
|
371 |
+ rooms_mut.unlock(); |
|
372 |
+ return; |
|
373 |
+ } |
|
374 |
+ bool p_exists = r->hasParticipant(call_tag); |
|
375 |
+ if (p_exists && (mute >= 0)) |
|
376 |
+ r->setMuted(call_tag, mute); |
|
377 |
+ |
|
378 |
+ rooms_mut.unlock(); |
|
379 |
+ |
|
380 |
+ if (p_exists) { |
|
381 |
+ AmSessionContainer::instance()->postEvent(call_tag, |
|
382 |
+ new WebConferenceEvent(id)); |
|
383 |
+ ret.push(0); |
|
384 |
+ ret.push("OK"); |
|
385 |
+ } else { |
|
386 |
+ ret.push(2); |
|
387 |
+ ret.push("call does not exist"); |
|
388 |
+ } |
|
389 |
+} |
|
390 |
+ |
|
391 |
+void WebConferenceFactory::kickout(const AmArgArray& args, AmArgArray& ret) { |
|
392 |
+ postConfEvent(args, ret, WebConferenceEvent::Kick, -1); |
|
393 |
+} |
|
394 |
+ |
|
395 |
+void WebConferenceFactory::mute(const AmArgArray& args, AmArgArray& ret) { |
|
396 |
+ postConfEvent(args, ret, WebConferenceEvent::Mute, 1); |
|
397 |
+} |
|
398 |
+ |
|
399 |
+void WebConferenceFactory::unmute(const AmArgArray& args, AmArgArray& ret) { |
|
400 |
+ postConfEvent(args, ret, WebConferenceEvent::Unmute, 0); |
|
401 |
+} |
|
402 |
+ |
|
403 |
+void WebConferenceFactory::serverInfo(const AmArgArray& args, AmArgArray& ret) { |
|
404 |
+ ret.push("Not yet implemented"); |
|
405 |
+} |
|
406 |
+ |
|
407 |
+WebConferenceDialog::WebConferenceDialog(AmPromptCollection& prompts, |
|
408 |
+ WebConferenceFactory* my_f, |
|
409 |
+ UACAuthCred* cred) |
|
410 |
+ : play_list(this), separator(this, 0), prompts(prompts), state(None), |
|
411 |
+ factory(my_f), cred(cred) |
|
412 |
+{ |
|
413 |
+ is_dialout = (cred != NULL); |
|
414 |
+ // set configured playout type |
|
415 |
+ rtp_str.setPlayoutType(WebConferenceFactory::m_PlayoutType); |
|
416 |
+} |
|
417 |
+ |
|
418 |
+WebConferenceDialog::~WebConferenceDialog() |
|
419 |
+{ |
|
420 |
+ prompts.cleanup((long)this); |
|
421 |
+ if (InConference == state) { |
|
422 |
+ factory->updateStatus(conf_id, |
|
423 |
+ getLocalTag(), |
|
424 |
+ ConferenceRoomParticipant::Finished, |
|
425 |
+ "out"); |
|
426 |
+ } |
|
427 |
+} |
|
428 |
+ |
|
429 |
+void WebConferenceDialog::connectConference(const string& room) { |
|
430 |
+ // set the conference id ('conference room') |
|
431 |
+ conf_id = room; |
|
432 |
+ |
|
433 |
+ // disconnect in/out for safety |
|
434 |
+ setInOut(NULL, NULL); |
|
435 |
+ |
|
436 |
+ // we need to be in the same callgroup as the other |
|
437 |
+ // people in the conference (important if we have multiple |
|
438 |
+ // MediaProcessor threads |
|
439 |
+ changeCallgroup(conf_id); |
|
440 |
+ |
|
441 |
+ // get a channel from the status |
|
442 |
+ channel.reset(AmConferenceStatus::getChannel(conf_id,getLocalTag())); |
|
443 |
+ |
|
444 |
+ // clear the playlist |
|
445 |
+ play_list.close(); |
|
446 |
+ |
|
447 |
+ // add the channel to our playlist |
|
448 |
+ play_list.addToPlaylist(new AmPlaylistItem(channel.get(), |
|
449 |
+ channel.get())); |
|
450 |
+ |
|
451 |
+ // set the playlist as input and output |
|
452 |
+ setInOut(&play_list,&play_list); |
|
453 |
+ |
|
454 |
+} |
|
455 |
+ |
|
456 |
+void WebConferenceDialog::onSessionStart(const AmSipRequest& req) { |
|
457 |
+ state = EnteringPin; |
|
458 |
+ |
|
459 |
+ prompts.addToPlaylist(ENTER_PIN, (long)this, play_list); |
|
460 |
+ |
|
461 |
+ // set the playlist as input and output |
|
462 |
+ setInOut(&play_list,&play_list); |
|
463 |
+} |
|
464 |
+ |
|
465 |
+void WebConferenceDialog::onSessionStart(const AmSipReply& rep) { |
|
466 |
+ state = InConference; |
|
467 |
+ connectConference(dlg.user); |
|
468 |
+} |
|
469 |
+ |
|
470 |
+void WebConferenceDialog::onSipReply(const AmSipReply& reply) { |
|
471 |
+ DBG("SIP REPLY ----------------------\n"); |
|
472 |
+ AmSession::onSipReply(reply); |
|
473 |
+ |
|
474 |
+ if (is_dialout) { |
|
475 |
+ DBG("is_dialout"); |
|
476 |
+ // map AmSipDialog state to WebConferenceState |
|
477 |
+ ConferenceRoomParticipant::ParticipantStatus rep_st = ConferenceRoomParticipant::Connecting; |
|
478 |
+ switch (dlg.getStatus()) { |
|
479 |
+ case AmSipDialog::Pending: { |
|
480 |
+ rep_st = ConferenceRoomParticipant::Connecting; |
|
481 |
+ if (reply.code == 180) |
|
482 |
+ rep_st = ConferenceRoomParticipant::Ringing; |
|
483 |
+ } break; |
|
484 |
+ case AmSipDialog::Connected: |
|
485 |
+ rep_st = ConferenceRoomParticipant::Connected; break; |
|
486 |
+ case AmSipDialog::Disconnecting: |
|
487 |
+ rep_st = ConferenceRoomParticipant::Disconnecting; break; |
|
488 |
+ } |
|
489 |
+ DBG("is dialout: updateing status\n"); |
|
490 |
+ factory->updateStatus(dlg.user, getLocalTag(), |
|
491 |
+ rep_st, int2str(reply.code) + " " + reply.reason); |
|
492 |
+ } |
|
493 |
+} |
|
494 |
+ |
|
495 |
+void WebConferenceDialog::onBye(const AmSipRequest& req) |
|
496 |
+{ |
|
497 |
+ if (InConference == state) { |
|
498 |
+ factory->updateStatus(conf_id, |
|
499 |
+ getLocalTag(), |
|
500 |
+ ConferenceRoomParticipant::Disconnecting, |
|
501 |
+ req.method); |
|
502 |
+ } |
|
503 |
+ |
|
504 |
+ disconnectConference(); |
|
505 |
+} |
|
506 |
+ |
|
507 |
+void WebConferenceDialog::disconnectConference() { |
|
508 |
+ play_list.close(); |
|
509 |
+ setInOut(NULL,NULL); |
|
510 |
+ channel.reset(NULL); |
|
511 |
+ setStopped(); |
|
512 |
+} |
|
513 |
+ |
|
514 |
+void WebConferenceDialog::process(AmEvent* ev) |
|
515 |
+{ |
|
516 |
+ // check conference events |
|
517 |
+ ConferenceEvent* ce = dynamic_cast<ConferenceEvent*>(ev); |
|
518 |
+ if(ce && (conf_id == ce->conf_id)){ |
|
519 |
+ switch(ce->event_id){ |
|
520 |
+ |
|
521 |
+ case ConfNewParticipant: { |
|
522 |
+ DBG("########## new participant #########\n"); |
|
523 |
+ if(ce->participants == 1){ |
|
524 |
+ prompts.addToPlaylist(FIRST_PARTICIPANT, (long)this, play_list, true); |
|
525 |
+ } else { |
|
526 |
+ prompts.addToPlaylist(JOIN_SOUND, (long)this, play_list, true); |
|
527 |
+ } |
|
528 |
+ } break; |
|
529 |
+ |
|
530 |
+ case ConfParticipantLeft: { |
|
531 |
+ DBG("########## participant left ########\n"); |
|
532 |
+ prompts.addToPlaylist(DROP_SOUND, (long)this, play_list, true); |
|
533 |
+ } break; |
|
534 |
+ |
|
535 |
+ default: |
|
536 |
+ break; |
|
537 |
+ } |
|
538 |
+ return; |
|
539 |
+ } |
|
540 |
+ |
|
541 |
+ // our item will fire this event |
|
542 |
+ AmPlaylistSeparatorEvent* sep_ev = dynamic_cast<AmPlaylistSeparatorEvent*>(ev); |
|
543 |
+ if (NULL != sep_ev) { |
|
544 |
+ // don't care for the id here |
|
545 |
+ if (EnteringConference == state) { |
|
546 |
+ state = InConference; |
|
547 |
+ DBG("connectConference. **********************\n"); |
|
548 |
+ connectConference(pin_str); |
|
549 |
+ factory->newParticipant(pin_str, |
|
550 |
+ getLocalTag(), |
|
551 |
+ dlg.remote_party); |
|
552 |
+ factory->updateStatus(pin_str, |
|
553 |
+ getLocalTag(), |
|
554 |
+ ConferenceRoomParticipant::Connected, |
|
555 |
+ "200 OK"); |
|
556 |
+ } |
|
557 |
+ } |
|
558 |
+ // audio events |
|
559 |
+ AmAudioEvent* audio_ev = dynamic_cast<AmAudioEvent*>(ev); |
|
560 |
+ if (audio_ev && |
|
561 |
+ audio_ev->event_id == AmAudioEvent::noAudio) { |
|
562 |
+ DBG("received noAudio event. **********************\n"); |
|
563 |
+ return; |
|
564 |
+ } |
|
565 |
+ |
|
566 |
+ WebConferenceEvent* webconf_ev = dynamic_cast<WebConferenceEvent*>(ev); |
|
567 |
+ if (NULL != webconf_ev) { |
|
568 |
+ if (InConference == state) { |
|
569 |
+ switch(webconf_ev->event_id) { |
|
570 |
+ case WebConferenceEvent::Kick: { |
|
571 |
+ dlg.bye(); |
|
572 |
+ disconnectConference(); |
|
573 |
+ factory->updateStatus(conf_id, |
|
574 |
+ getLocalTag(), |
|
575 |
+ ConferenceRoomParticipant::Disconnecting, |
|
576 |
+ "disconnect"); |
|
577 |
+ } break; |
|
578 |
+ case WebConferenceEvent::Mute: { setInOut(NULL, &play_list); } break; |
|
579 |
+ case WebConferenceEvent::Unmute:{ setInOut(&play_list, &play_list); } break; |
|
580 |
+ default: { WARN("ignoring unknown webconference event %d\n", webconf_ev->event_id); } break; |
|
581 |
+ } |
|
582 |
+ } |
|
583 |
+ return; |
|
584 |
+ } |
|
585 |
+ |
|
586 |
+ AmSession::process(ev); |
|
587 |
+} |
|
588 |
+ |
|
589 |
+void WebConferenceDialog::onDtmf(int event, int duration) |
|
590 |
+{ |
|
591 |
+ DBG("WebConferenceDialog::onDtmf: event %d duration %d\n", |
|
592 |
+ event, duration); |
|
593 |
+ |
|
594 |
+ if (EnteringPin == state) { |
|
595 |
+ // not yet in conference |
|
596 |
+ if (event<10) { |
|
597 |
+ pin_str += int2str(event); |
|
598 |
+ DBG("added '%s': PIN is now '%s'.\n", |
|
599 |
+ int2str(event).c_str(), pin_str.c_str()); |
|
600 |
+ } else if (event==10 || event==11) { |
|
601 |
+ // pound and star key |
|
602 |
+ // if required add checking of pin here... |
|
603 |
+ if (!pin_str.length()) { |
|
604 |
+ |
|
605 |
+ prompts.addToPlaylist(WRONG_PIN, (long)this, play_list, true); |
|
606 |
+ } else { |
|
607 |
+ state = EnteringConference; |
|
608 |
+ setInOut(NULL, NULL); |
|
609 |
+ play_list.close(); |
|
610 |
+ for (size_t i=0;i<pin_str.length();i++) { |
|
611 |
+ string num = ""; |
|
612 |
+ num[0] = pin_str[i]; |
|
613 |
+ DBG("adding '%s' to playlist.\n", num.c_str()); |
|
614 |
+ |
|
615 |
+ prompts.addToPlaylist(num, |
|
616 |
+ (long)this, play_list); |
|
617 |
+ } |
|
618 |
+ |
|
619 |
+ setInOut(&play_list,&play_list); |
|
620 |
+ prompts.addToPlaylist(ENTERING_CONFERENCE, |
|
621 |
+ (long)this, play_list); |
|
622 |
+ play_list.addToPlaylist(new AmPlaylistItem(&separator, NULL)); |
|
623 |
+ } |
|
624 |
+ } |
|
625 |
+ } |
|
626 |
+} |
|
627 |
+ |
0 | 628 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,176 @@ |
1 |
+/* |
|
2 |
+ * $Id: PinAuthConference.h 288 2007-03-28 16:32:02Z sayer $ |
|
3 |
+ * |
|
4 |
+ * Copyright (C) 2007 iptego GmbH |
|
5 |
+ * |
|
6 |
+ * This file is part of sems, a free SIP media server. |
|
7 |
+ * |
|
8 |
+ * sems is free software; you can redistribute it and/or modify |
|
9 |
+ * it under the terms of the GNU General Public License as published by |
|
10 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
11 |
+ * (at your option) any later version. |
|
12 |
+ * |
|
13 |
+ * For a license to use the sems software under conditions |
|
14 |
+ * other than those described here, or to purchase support for this |
|
15 |
+ * software, please contact iptel.org by e-mail at the following addresses: |
|
16 |
+ * info@iptel.org |
|
17 |
+ * |
|
18 |
+ * sems is distributed in the hope that it will be useful, |
|
19 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
20 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
21 |
+ * GNU General Public License for more details. |
|
22 |
+ * |
|
23 |
+ * You should have received a copy of the GNU General Public License |
|
24 |
+ * along with this program; if not, write to the Free Software |
|
25 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
26 |
+ */ |
|
27 |
+#ifndef _PINAUTHCONFERENCE_H_ |
|
28 |
+#define _PINAUTHCONFERENCE_H_ |
|
29 |
+ |
|
30 |
+#include "AmApi.h" |
|
31 |
+#include "AmSession.h" |
|
32 |
+#include "AmAudio.h" |
|
33 |
+#include "AmConferenceChannel.h" |
|
34 |
+#include "AmPlaylist.h" |
|
35 |
+#include "AmPromptCollection.h" |
|
36 |
+#include "ampi/UACAuthAPI.h" |
|
37 |
+ |
|
38 |
+#include "RoomInfo.h" |
|
39 |
+ |
|
40 |
+#include <map> |
|
41 |
+#include <string> |
|
42 |
+using std::map; |
|
43 |
+using std::string; |
|
44 |
+ |
|
45 |
+class ConferenceStatus; |
|
46 |
+class ConferenceStatusContainer; |
|
47 |
+ |
|
48 |
+// configuration parameter names |
|
49 |
+#define ENTERING_CONFERENCE "entering_conference" |
|
50 |
+#define FIRST_PARTICIPANT "first_participant" |
|
51 |
+#define JOIN_SOUND "join_sound" |
|
52 |
+#define DROP_SOUND "drop_sound" |
|
53 |
+#define ENTER_PIN "enter_pin" |
|
54 |
+#define WRONG_PIN "wrong_pin" |
|
55 |
+ |
|
56 |
+// default path for files |
|
57 |
+#define ANNOUNCE_PATH "../apps/examples/webconference/" |
|
58 |
+ |
|
59 |
+class WebConferenceEvent : public AmEvent |
|
60 |
+{ |
|
61 |
+public: |
|
62 |
+ WebConferenceEvent(int id) : AmEvent(id) { } |
|
63 |
+ enum { Kick, |
|
64 |
+ Mute, |
|
65 |
+ Unmute |
|
66 |
+ }; |
|
67 |
+}; |
|
68 |
+ |
|
69 |
+class WebConferenceFactory |
|
70 |
+ : public AmSessionFactory, |
|
71 |
+ public AmDynInvokeFactory, |
|
72 |
+ public AmDynInvoke |
|
73 |
+{ |
|
74 |
+ AmPromptCollection prompts; |
|
75 |
+ |
|
76 |
+ map<string, ConferenceRoom> rooms; |
|
77 |
+ AmMutex rooms_mut; |
|
78 |
+ |
|
79 |
+ // for DI |
|
80 |
+ static WebConferenceFactory* _instance; |
|
81 |
+ bool configured; |
|
82 |
+ |
|
83 |
+ string getRandomPin(); |
|
84 |
+ /** returns NULL if adminpin wrong */ |
|
85 |
+ ConferenceRoom* getRoom(const string& room, |
|
86 |
+ const string& adminpin); |
|
87 |
+ void postConfEvent(const AmArgArray& args, AmArgArray& ret, |
|
88 |
+ int id, int mute); |
|
89 |
+public: |
|
90 |
+ static string DigitsDir; |
|
91 |
+ static PlayoutType m_PlayoutType; |
|
92 |
+ |
|
93 |
+ WebConferenceFactory(const string& _app_name); |
|
94 |
+ AmSession* onInvite(const AmSipRequest&); |
|
95 |
+ AmSession* onInvite(const AmSipRequest& req, |
|
96 |
+ AmArg& session_params); |
|
97 |
+ int onLoad(); |
|
98 |
+ |
|
99 |
+ inline void newParticipant(const string& conf_id, |
|
100 |
+ const string& localtag, |
|
101 |
+ const string& number); |
|
102 |
+ inline void updateStatus(const string& conf_id, |
|
103 |
+ const string& localtag, |
|
104 |
+ ConferenceRoomParticipant::ParticipantStatus status, |
|
105 |
+ const string& reason); |
|
106 |
+ |
|
107 |
+ // DI API |
|
108 |
+ WebConferenceFactory* getInstance(){ |
|
109 |
+ return _instance; |
|
110 |
+ } |
|
111 |
+ void invoke(const string& method, const AmArgArray& args, AmArgArray& ret); |
|
112 |
+ |
|
113 |
+ // DI functions |
|
114 |
+ void roomCreate(const AmArgArray& args, AmArgArray& ret); |
|
115 |
+ void roomInfo(const AmArgArray& args, AmArgArray& ret); |
|
116 |
+ void dialout(const AmArgArray& args, AmArgArray& ret); |
|
117 |
+ void kickout(const AmArgArray& args, AmArgArray& ret); |
|
118 |
+ void mute(const AmArgArray& args, AmArgArray& ret); |
|
119 |
+ void unmute(const AmArgArray& args, AmArgArray& ret); |
|
120 |
+ void serverInfo(const AmArgArray& args, AmArgArray& ret); |
|
121 |
+}; |
|
122 |
+ |
|
123 |
+class WebConferenceDialog |
|
124 |
+ : public AmSession, |
|
125 |
+ public CredentialHolder |
|
126 |
+{ |
|
127 |
+public: |
|
128 |
+ enum WebConferenceState { |
|
129 |
+ None, |
|
130 |
+ EnteringPin, |
|
131 |
+ EnteringConference, |
|
132 |
+ InConference |
|
133 |
+ }; |
|
134 |
+ |
|
135 |
+private: |
|
136 |
+ AmPlaylist play_list; |
|
137 |
+ AmPlaylistSeparator separator; |
|
138 |
+ |
|
139 |
+ AmPromptCollection& prompts; |
|
140 |
+ |
|
141 |
+ // our connection to the conference |
|
142 |
+ auto_ptr<AmConferenceChannel> channel; |
|
143 |
+ string conf_id; |
|
144 |
+ string pin_str; |
|
145 |
+ |
|
146 |
+ void connectConference(const string& room); |
|
147 |
+ void disconnectConference(); |
|
148 |
+ |
|
149 |
+ WebConferenceState state; |
|
150 |
+ |
|
151 |
+ WebConferenceFactory* factory; |
|
152 |
+ bool is_dialout; |
|
153 |
+ UACAuthCred* cred; |
|
154 |
+ |
|
155 |
+public: |
|
156 |
+ WebConferenceDialog(AmPromptCollection& prompts, |
|
157 |
+ WebConferenceFactory* my_f, |
|
158 |
+ UACAuthCred* cred); |
|
159 |
+ ~WebConferenceDialog(); |
|
160 |
+ |
|
161 |
+ void process(AmEvent* ev); |
|
162 |
+ void onSipReply(const AmSipReply& reply); |
|
163 |
+ void onSessionStart(const AmSipRequest& req); |
|
164 |
+ void onSessionStart(const AmSipReply& rep); |
|
165 |
+ void onDtmf(int event, int duration); |
|
166 |
+ void onBye(const AmSipRequest& req); |
|
167 |
+ |
|
168 |
+ UACAuthCred* getCredentials() { return cred; } |
|
169 |
+ |
|
170 |
+}; |
|
171 |
+ |
|
172 |
+#endif |
|
173 |
+// Local Variables: |
|
174 |
+// mode:C++ |
|
175 |
+// End: |
|
176 |
+ |
0 | 177 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,12 @@ |
1 |
+ |
|
2 |
+# configure the various announcements here |
|
3 |
+first_participant=/usr/local/lib/sems/audio/webconference/first_participant.wav |
|
4 |
+join_sound=/usr/local/lib/sems/audio/webconference/beep.wav |
|
5 |
+drop_sound=/usr/local/lib/sems/audio/webconference/beep.wav |
|
6 |
+enter_pin=/usr/local/lib/sems/audio/webconference/pin_prompt.wav |
|
7 |
+wrong_pin=/usr/local/lib/sems/audio/webconference/wrong_pin.wav |
|
8 |
+entering_conference=/usr/local/lib/sems/audio/webconference/entering_conference.wav |
|
9 |
+ |
|
10 |
+# digits to play the room number |
|
11 |
+# must contain the files 0.wav, 1.wav, ..., 9.wav |
|
12 |
+digits_dir=/usr/local/lib/sems/audio/webconference/ |
|
0 | 13 |
\ No newline at end of file |