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