1 /*
2 * Copyright (C) 2006-2007 iptego GmbH
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 #ifndef _AM_B2ABSession_H
26 #define _AM_B2ABSession_H
27
28 #include "AmSession.h"
29 #include "AmSipDialog.h"
30 #include "AmAdvancedAudio.h"
31 #include "SampleArray.h"
32 #include <string>
33 using std::string;
AmB2ABSession()34
35 #include <map>
36
37 class AmSessionAudioConnector;
38
AmB2ABSession(const string & other_local_tag)39 enum { B2ABTerminateLeg,
40 B2ABConnectLeg,
41 B2ABConnectEarlyAudio,
42 B2ABConnectAudio,
43 B2ABConnectOtherLegFailed,
44 B2ABConnectOtherLegException,
45 B2ABOtherLegRinging
46 };
47
48 /** \brief base class for event in B2AB session */
clear_other()49 struct B2ABEvent: public AmEvent
50 {
51 B2ABEvent(int ev_id)
52 : AmEvent(ev_id)
53 {}
54 };
55
56 struct B2ABOtherLegRingingEvent: public B2ABEvent
57 {
58 B2ABOtherLegRingingEvent()
process(AmEvent * event)59 : B2ABEvent(B2ABOtherLegRinging)
60 {}
61 };
62
63 /** \brief trigger connecting the audio in B2AB session */
64 struct B2ABConnectAudioEvent: public B2ABEvent
65 {
66 B2ABConnectAudioEvent()
67 : B2ABEvent(B2ABConnectAudio)
68 {}
69 };
onB2ABEvent(B2ABEvent * ev)70
71 /** \brief trigger connecting the audio in B2AB session */
72 struct B2ABConnectEarlyAudioEvent: public B2ABEvent
73 {
74 B2ABConnectEarlyAudioEvent()
75 : B2ABEvent(B2ABConnectEarlyAudio)
76 {}
77 };
78
79 /** \brief trigger connecting the callee leg in B2AB session */
relayEvent(AmEvent * ev)80 struct B2ABConnectLegEvent: public B2ABEvent
81 {
82 string remote_party;
83 string remote_uri;
84 string local_party;
85 string local_uri;
86 string callgroup;
87 string headers;
88
89 B2ABConnectLegEvent(const string& remote_party,
90 const string& remote_uri,
91 const string& local_party,
92 const string& local_uri,
93 const string& callgroup,
94 const string& headers = "")
95 : B2ABEvent(B2ABConnectLeg),
96 remote_party(remote_party),
97 remote_uri(remote_uri),
98 local_party(local_party),
99 local_uri(local_uri),
100 callgroup(callgroup),
101 headers(headers)
102 {}
103 };
104
105 /** \brief event fired if an exception occured while creating B leg */
106 struct B2ABConnectOtherLegExceptionEvent: public B2ABEvent {
onBye(const AmSipRequest & req)107
108 unsigned int code;
109 string reason;
110
111 B2ABConnectOtherLegExceptionEvent(unsigned int code,
112 const string& reason)
terminateLeg()113 : B2ABEvent(B2ABConnectOtherLegException),
114 code(code), reason(reason)
115 {}
116 };
117
118 /** \brief event fired if the B leg could not be connected (e.g. busy) */
119 struct B2ABConnectOtherLegFailedEvent: public B2ABEvent {
terminateOtherLeg()120
121 unsigned int code;
122 string reason;
123
124 B2ABConnectOtherLegFailedEvent(unsigned int code,
125 const string& reason)
AmB2ABCallerSession()126 : B2ABEvent(B2ABConnectOtherLegFailed),
127 code(code), reason(reason)
128 {}
129 };
130
131 /**
132 * \brief Base class for Sessions in B2ABUA mode.
133 *
~AmB2ABCallerSession()134 * It has two legs: Callee- and caller-leg.
135 */
136 class AmB2ABSession: public AmSession
137 {
138
139 protected:
140
141 /** local tag of the other leg */
142 string other_id;
143
144 /** reference to the audio connector - caution: not owned by callee dialog! */
145 AmSessionAudioConnector* connector;
146
147 /** Requests received for relaying */
148 std::map<int,AmSipRequest> recvd_req;
149
150 void clear_other();
151
152 /** Relay one event to the other side. */
153 virtual void relayEvent(AmEvent* ev);
154
155 /** Terminate our leg and forget the other. */
156 virtual void terminateLeg();
157
158 /** Terminate the other leg and forget it.*/
159 virtual void terminateOtherLeg();
160
161
162 /** B2ABEvent handler */
163 virtual void onB2ABEvent(B2ABEvent* ev);
164
165 /* // Other leg received a BYE */
166 /* virtual void onOtherBye(const AmSipRequest& req); */
167
168 /* /\** INVITE from other leg has been replied *\/ */
169 /* virtual void onOtherReply(const AmSipReply& reply); */
170
171 /** @see AmEventQueue */
172 void process(AmEvent* event);
173
174 public:
175
176 AmB2ABSession();
177 AmB2ABSession(const string& other_local_tag);
178 virtual ~AmB2ABSession();
179
180 void onBye(const AmSipRequest& req);
181
182 /** connect audio stream to the other session */
183 virtual void connectSession();
184
185 /** reverse operation of connectSession */
186 void disconnectSession();
187
188 };
189
190 class AmB2ABCalleeSession;
191
192 /** \brief Caller leg of a B2AB session */
193 class AmB2ABCallerSession: public AmB2ABSession
194 {
195 public:
196 enum CalleeStatus {
197 None=0,
198 NoReply,
199 Early,
200 Ringing,
201 Connected
202 };
203
connectCallee(const string & remote_party,const string & remote_uri,const string & local_party,const string & local_uri,const string & headers)204 private:
205 // Callee Status
206 CalleeStatus callee_status;
207
208 virtual void setupCalleeSession(AmB2ABCalleeSession* callee_session,
209 B2ABConnectLegEvent* ev);
210
211 protected:
212
213 virtual AmB2ABCalleeSession* createCalleeSession();
214 void relayEvent(AmEvent* ev);
215
216 public:
217 AmB2ABCallerSession();
218 ~AmB2ABCallerSession();
219
220 CalleeStatus getCalleeStatus() { return callee_status; }
221
relayEvent(AmEvent * ev)222 void connectCallee(const string& remote_party,
223 const string& remote_uri,
224 const string& local_party,
225 const string& local_uri,
226 const string& headers = "");
227
228 // @see AmB2ABSession
229 void terminateOtherLeg();
230
231 protected:
232 void onB2ABEvent(B2ABEvent* ev);
233 void onBeforeDestroy();
234 };
235
236 /** \brief Callee leg of a B2AB session */
setupCalleeSession(AmB2ABCalleeSession * callee_session,B2ABConnectLegEvent * ev)237 class AmB2ABCalleeSession: public AmB2ABSession
238 {
239 bool is_connected;
240
241 public:
242 AmB2ABCalleeSession(const string& other_local_tag,
243 AmSessionAudioConnector* callers_connector);
244 ~AmB2ABCalleeSession();
245
246 void onEarlySessionStart();
247 void onSessionStart();
248 void onSipReply(const AmSipRequest& req, const AmSipReply& rep,
249 AmSipDialog::Status old_dlg_status);
250
251 protected:
252 void onB2ABEvent(B2ABEvent* ev);
253 void onBeforeDestroy();
254 AmCondition<bool>* released;
255 };
256
257 /** BRIDGE_DELAY is needed because of possible different packet sizes */
258 #define BRIDGE_DELAY (30.0/1000.0) // 30ms
259
260 /**
261 * \brief connects the audio of two sessions together
262 */
createCalleeSession()263 class AmSessionAudioConnector {
264
265 private:
266 AmAudioDelay audio_connectors[2];
267 string tag_sess[2];
268 bool connected[2];
269 AmMutex tag_mut;
270
271 AmCondition<bool> released;
272
273 public:
274 /** create a connector, connect audio to sess */
275 AmSessionAudioConnector()
276 : released(true)
277 {
278 connected[0] = false;
279 connected[1] = false;
280 audio_connectors[0].setDelay(BRIDGE_DELAY);
281 audio_connectors[1].setDelay(BRIDGE_DELAY);
282 }
283
284 ~AmSessionAudioConnector() {}
285
286 /** connect audio to sess */
287 void connectSession(AmSession* sess);
288
289 /** disconnect session
290 * @return whether connector is still connected after disconnect
291 */
292 bool disconnectSession(AmSession* sess);
293
294 /** mark as in use by entity not owning it */
295 void block();
296
297 /** mark as released by entity not owning it */
298 void release();
299
300 /** wait until released by everyone */
301 void waitReleased();
302 };
303
304 #endif
305
306 // Local Variables:
307 // mode:C++
308 // End:
309
310