1 /*
2  * Copyright (C) 2006 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 
26 #include "Jukecall.h"
27 #include "AmApi.h"
28 #include "AmUtils.h"
29 #include "sems.h"
30 #include "log.h"
31 
32 #define MOD_NAME "jukecall"
33 
34 EXPORT_SESSION_FACTORY(JukecallFactory,MOD_NAME);
35 
36 // you can replace this with configurable file
37 #define INITIAL_ANNOUNCEMENT "../apps/examples/jukecall/wav/greeting.wav"
38 #define JUKE_DIR             "../apps/examples/jukecall/wav/"
39 
40 JukecallFactory::JukecallFactory(const string& _app_name)
41   : AmSessionFactory(_app_name)
42 {
43 }
44 
45 
46 int JukecallFactory::onLoad()
47 {
48   // read configuration
49 
50   DBG("JukecallFactory loaded.\n");
51   return 0;
52 }
53 
54 AmSession* JukecallFactory::onInvite(const AmSipRequest& req, const string& app_name,
55 				     const map<string,string>& app_params)
56 {
57   if (req.user.length() <= 3) {
58     throw AmSession::Exception(403, "Need a number to call");
59   }
60 
61   JukecallSession* dlg = new JukecallSession();
62 
63   return dlg;
64 }
65 
66 JukecallSession::JukecallSession()
67   : AmB2ABCallerSession(), state(JC_none)
68 {
69 }
70 
71 JukecallSession::~JukecallSession()
72 {
73 }
74 
75 void JukecallSession::onSessionStart()
76 {
77   if (state != JC_none) {
78     // reinvite
79     AmB2ABCallerSession::onSessionStart();
80     return;
81   }
82 
83   DBG("-----------------------------------------------------------------\n");
84   DBG("playing file\n");
85 
86   if(initial_announcement.open(INITIAL_ANNOUNCEMENT,AmAudioFile::Read)) {
87     dlg->bye();
88     throw string("CTConfDDialog::onSessionStart: Cannot open file '%s'\n", INITIAL_ANNOUNCEMENT);
89   }
90 
91   // set this as our output
92   setOutput(&initial_announcement);
93 
94   state = JC_initial_announcement;
95 
96   AmB2ABCallerSession::onSessionStart();
97 }
98 
99 void JukecallSession::onDtmf(int event, int duration_msec) {
100   DBG("got DTMF %d\n", event);
101 
102   // no jukebox if other party is not connected
103   if (getCalleeStatus()!=AmB2ABCallerSession::Connected)
104     return;
105 
106   // no jukebox in the beginning and while playing
107   if (state != JC_connect)
108     return;
109 
110   DBG("playing back file...\n");
111 
112   song.reset(new AmAudioFile());
113   if (song->open(JUKE_DIR+int2str(event)+".wav",AmAudioFile::Read)) {
114     ERROR("could not open file\n");
115     return;
116   }
117   setOutput(song.get());
118   state = JC_juke;
119 
120   relayEvent(new JukeEvent(event));
121 }
122 
123 void JukecallSession::process(AmEvent* event)
124 {
125 
126   AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(event);
127   if(audio_event && (audio_event->event_id == AmAudioEvent::cleared)){
128     switch(state) {
129     case JC_initial_announcement: {
130       state = JC_connect;
131       string callee = "sip:" + dlg->getUser().substr(3) + "@" + dlg->getDomain();
132       DBG("-------------------------- connecting %s ------------------------\n", callee.c_str());
133       connectCallee(callee, callee,
134 		    dlg->getRemoteParty(), dlg->getRemoteUri());
135 
136       return;
137 
138     } break;
139 
140     case JC_juke: {
141       DBG("reconnecting audio\n");
142       connectSession();
143       state = JC_connect;
144       return;
145     }; break;
146 
147     default: {
148       DBG("cleared in other state.\n");
149       return;
150     };
151     }
152 
153   }
154 
155   AmB2ABCallerSession::process(event);
156 }
157 
158 AmB2ABCalleeSession* JukecallSession::createCalleeSession() {
159   AmB2ABCalleeSession* sess = new JukecalleeSession(getLocalTag(), connector);
160   return sess;
161 }
162 
163 JukecalleeSession::JukecalleeSession(const string& other_tag,
164 				     AmSessionAudioConnector* connector)
165   : AmB2ABCalleeSession(other_tag, connector)
166 {
167   setDtmfDetectionEnabled(false);
168 }
169 
170 
171 void JukecalleeSession::process(AmEvent* event) {
172   JukeEvent* juke_event = dynamic_cast<JukeEvent*>(event);
173   if(juke_event) {
174     song.reset(new AmAudioFile());
175     if (song->open(JUKE_DIR+int2str(event->event_id)+".wav",AmAudioFile::Read)) {
176       ERROR("could not open file\n");
177       return;
178     }
179     setOutput(song.get());
180     return;
181   }
182 
183   AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(event);
184   if(audio_event && (audio_event->event_id == AmAudioEvent::cleared)){
185     DBG("reconnecting audio\n");
186     connectSession();
187     return;
188   }
189 
190   AmB2ABCalleeSession::process(event);
191 }
192