f446ea430b4a73dfff4bd8fd40172dac396dad4a
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

1) /* Blinker
Stefan Schuermans update copyright header

Stefan Schuermans authored 5 years ago

2)    Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

3)    Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4)    a blinkenarea.org project */
5) 
6) #include <chrono>
7) #include <condition_variable>
8) #include <iostream>
9) #include <mutex>
10) #include <sstream>
11) #include <stdarg.h>
12) #include <stdio.h>
13) #include <string>
14) #include <string.h>
15) #include <thread>
16) 
17) #ifdef BLINKER_CFG_LINPHONE
18) #include <linphone/linphonecore.h>
19) #endif
20) 
21) #include "Directory.h"
22) #include "File.h"
23) #include "Module.h"
24) #include "NameFile.h"
25) #include "OpConn.h"
26) #include "OpConnIf.h"
27) #include "SipPhone.h"
28) #include "Time.h"
29) #include "TimeCallee.h"
30) 
31) namespace Blinker {
32) 
33) #ifdef BLINKER_CFG_LINPHONE
34) 
35) /**
36)  * everything using the linphone library happens in a separate thread,
37)  * because some call to linphone take long (up to two seconds)
38)  */
39) namespace linphone {
40) 
41) static char const *loglevel2str(OrtpLogLevel lev)
42) {
43)   switch(lev) {
44)   case ORTP_DEBUG: return "DEBUG";
45)   case ORTP_MESSAGE: return "MESSAGE";
46)   case ORTP_WARNING: return "WARNING";
47)   case ORTP_ERROR: return "ERROR";
48)   case ORTP_FATAL: return "FATAL";
49)   case ORTP_TRACE: return "TRACE";
50)   case ORTP_LOGLEV_END: return "LOGLEV_END";
51)   default: return "?";
52)   }
53) }
54) 
55) static char const *gstate2str(LinphoneGlobalState gstate)
56) {
57)   switch (gstate) {
58)   case LinphoneGlobalOff: return "Off";
59)   case LinphoneGlobalStartup: return "Startup";
60)   case LinphoneGlobalOn: return "On";
61)   case LinphoneGlobalShutdown: return "Shutdown";
62)   default: return "?";
63)   }
64) }
65) 
66) static char const *rstate2str(LinphoneRegistrationState rstate)
67) {
68)   switch (rstate) {
69)   case LinphoneRegistrationNone: return "None";
70)   case LinphoneRegistrationProgress: return "Progress";
71)   case LinphoneRegistrationOk: return "Ok";
72)   case LinphoneRegistrationCleared: return "Cleared";
73)   case LinphoneRegistrationFailed: return "Failed";
74)   default: return "?";
75)   }
76) }
77) 
78) static char const *cstate2str(LinphoneCallState cstate)
79) {
80)   switch (cstate) {
81)   case LinphoneCallIdle: return "Idle";
82)   case LinphoneCallIncomingReceived: return "IncomingReceived";
83)   case LinphoneCallOutgoingInit: return "OutgoingInit";
84)   case LinphoneCallOutgoingProgress: return "OutgoingProgress";
85)   case LinphoneCallOutgoingRinging: return "OutgoingRinging";
86)   case LinphoneCallOutgoingEarlyMedia: return "OutgoingEarlyMedia";
87)   case LinphoneCallConnected: return "Connected";
88)   case LinphoneCallStreamsRunning: return "StreamsRunning";
89)   case LinphoneCallPausing: return "Pausing";
90)   case LinphoneCallPaused: return "Paused";
91)   case LinphoneCallResuming: return "Resuming";
92)   case LinphoneCallRefered: return "Refered";
93)   case LinphoneCallError: return "Error";
94)   case LinphoneCallEnd: return "End";
95)   case LinphoneCallPausedByRemote: return "PausedByRemote";
96)   case LinphoneCallUpdatedByRemote: return "UpdatedByRemote";
97)   case LinphoneCallIncomingEarlyMedia: return "IncomingEarlyMedia";
98)   case LinphoneCallUpdating: return "Updating";
99)   case LinphoneCallReleased: return "Released";
100)   default: return "?";
101)   }
102) }
103) 
104) std::string glLogFileName; ///< name of global log file
105) std::ofstream glLogStream; ///< stream to open global log file
106) unsigned int glLogLineCnt; ///< number of lines already logged
107) 
108) /**
109)  * @brief log information from linphone library
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

110)  * @param[in] domain log domain - ignored
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

111)  * @param[in] lev log level
112)  * @param[in] fmt format string
113)  * @param[in] args arguments to insert into format string
114)  */
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

115) void log_handler(const char *domain, OrtpLogLevel lev, const char *fmt,
116)                  va_list args)
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

117) {
118)   // (re-)open logfile on first line
119)   if (glLogLineCnt == 0) {
120)     // close old file and clean up (just to be on the safe side)
121)     glLogStream.close();
122)     glLogStream.clear();
123)     // keep previous log file
124)     rename(glLogFileName.c_str(), (glLogFileName + ".prev").c_str());
125)     // open new file
126)     glLogStream.open(glLogFileName.c_str(), std::ios::out);
127)   }
128)   // write log line
129)   char buffer[4096];
130)   vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
131)   buffer[sizeof(buffer) - 1] = 0;
132)   glLogStream << Time::now().toStr() << " "
133)               << loglevel2str(lev) << " " << buffer << std::endl;
134)   // count lines
135)   ++glLogLineCnt;
136)   // close file if maximum line count reached
137)   if (glLogLineCnt >= 10000) {
138)     // close old file and clean up
139)     glLogStream.close();
140)     glLogStream.clear();
141)     // reset line count, so new file is opened on next line
142)     glLogLineCnt = 0;
143)   }
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

144)   (void)domain;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

145) }
146) 
147) /// global init
148) void init(std::string const &logFileName)
149) {
150)   glLogFileName = logFileName;
151)   glLogLineCnt = 0;
152)   linphone_core_set_log_handler(log_handler);
153) }
154) 
155) /// data of SIP client worker thread
156) struct Data {
157)   SipPhone::ConfigData const *configData; ///< config data for worker thread
158)   SipPhone::SharedData *sharedData; ///< data shared with main Blinker thread
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

159)   LinphoneCoreCbs *callbacks; ///< callbacks object, if active
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

160)   LinphoneCore *lc; ///< linphone core object, if active
161)   LinphoneCall *call; ///< current call, if available
162)   std::string playback; ///< name of playback file
163)   std::ofstream logStream; ///< stream to open log file
164)   unsigned int logLineCnt; ///< number of lines already logged to file
165) };
166) 
167) /**
168)  * @breif set playback file
169)  * @param[in,out] data data of SIP client
170)  * @param[in] name name of sound file (without extension)
171)  */
172) void set_playback(Data &data, std::string const &name)
173) {
174)   Directory dir(data.configData->soundDir);
175)   data.playback = dir.getFile(name + ".wav").getPath();
176) }
177) 
178) void start_playback(Data &data)
179) {
180)   if (data.lc && ! data.playback.empty()) {
181)     linphone_core_set_play_file(data.lc, data.playback.c_str());
182)   }
183) }
184) 
185) /**
186)  * @brief write log message
187)  * @param[in,out] data data of SIP client
188)  * @param[in] line lie to log
189)  */
190) void log(Data &data, std::string const &line)
191) {
192)   // (re-)open logfile on first line
193)   if (data.logLineCnt == 0) {
194)     // close old file and clean up (just to be on the safe side)
195)     data.logStream.close();
196)     data.logStream.clear();
197)     // keep previous log file
198)     rename(data.configData->logFileName.c_str(),
199)            (data.configData->logFileName + ".prev").c_str());
200)     // open new file
201)     data.logStream.open(data.configData->logFileName.c_str(), std::ios::out);
202)   }
203)   // write log line
204)   data.logStream << Time::now().toStr() << " " << line << std::endl;
205)   // count lines
206)   ++data.logLineCnt;
207)   // close file if maximum line count reached
208)   if (data.logLineCnt >= 10000) {
209)     // close old file and clean up
210)     data.logStream.close();
211)     data.logStream.clear();
212)     // reset line count, so new file is opened on next line
213)     data.logLineCnt = 0;
214)   }
215) }
216) 
217) /**
218)  * @brief global SIP state changed
219)  * @param[in] lc linphone core object
220)  * @param[in] gstate new global SIP state
221)  * @param[in] message informational message
222)  */
223) void global_state_changed(struct _LinphoneCore *lc,
224)                           LinphoneGlobalState gstate,
225)                           const char *message)
226) {
227)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

228)   if (data == nullptr) {
229)     return; // still initializing -> ignore
230)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

231) 
232)   std::stringstream line;
233)   line << "global state changed to " << gstate2str(gstate) << ": " << message;
234)   log(*data, line.str());
235) }
236) 
237) /**
238)  * @brief registration state changed
239)  * @param[in] lc linphone core object
240)  * @param[in] cfg proxy configuration
241)  * @param[in] rstate new registration state
242)  * @param[in] message informational message
243)  */
244) void registration_state_changed(struct _LinphoneCore *lc,
245)                                 LinphoneProxyConfig *cfg,
246)                                 LinphoneRegistrationState rstate,
247)                                 const char *message)
248) {
249)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

250)   if (data == nullptr) {
251)     return; // still initializing -> ignore
252)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

253)   (void)cfg;
254) 
255)   std::stringstream line;
256)   line << "registration state changed to " << rstate2str(rstate) << ": "
257)        << message;
258)   log(*data, line.str());
259) }
260) 
261) /**
262)  * @brief call state changed
263)  * @param[in] lc linphone core object
264)  * @param[in] call call object
265)  * @param[in] cstate new call state
266)  * @param[in] message informational message
267)  */
268) void call_state_changed(struct _LinphoneCore *lc, LinphoneCall *call,
269)                         LinphoneCallState cstate, const char *message)
270) {
271)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

272)   if (data == nullptr) {
273)     return; // still initializing -> ignore
274)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

275) 
276)   std::stringstream line;
277)   line << "call state changed to " << cstate2str(cstate) << ": "
278)        << message;
279)   log(*data, line.str());
280) 
281)   // current call -> handle state changes
282)   if (data->call == call) {
283)     switch (cstate) {
284)     case LinphoneCallStreamsRunning:
285)       start_playback(*data);
286)       break;
287)     case LinphoneCallRefered:
288)     case LinphoneCallError:
289)     case LinphoneCallEnd:
290)     case LinphoneCallReleased:
291)       data->call = nullptr;
292)       {
293)         std::lock_guard<std::mutex> lock(data->sharedData->mtx);
294)         data->sharedData->terminated = true;
295)       }
296)       break;
297)     default:
298)       break;
299)     }
300)   }
301)   // other call, but current call active -> reject call
302)   else if (data->call) {
303)     switch (cstate) {
304)     case LinphoneCallIncomingReceived:
305)       log(*data, "rejecting call (busy)");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

306)       linphone_call_decline(call, LinphoneReasonBusy);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

307)       break;
308)     default:
309)       break;
310)     }
311)   }
312)   // no call active -> accept call
313)   else {
314)     switch (cstate) {
315)     case LinphoneCallIncomingReceived:
316)       data->call = call;
317)       {
318)         std::lock_guard<std::mutex> lock(data->sharedData->mtx);
319)         data->sharedData->accepted = true;
320)       }
321)       data->playback.clear();
322)       log(*data, "accepting call");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

323)       linphone_call_accept(call);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

324)       break;
325)     default:
326)       break;
327)     }
328)   }
329) }
330) 
331) /**
332)  * @brief DTMF received
333)  * @param[in] lc linphone core object
334)  * @param[in] call call object
335)  * @param[in] dtmf DTMF as ASCII character
336)  */
337) void dtmf_received(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf)
338) {
339)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

340)   if (data == nullptr) {
341)     return; // still initializing -> ignore
342)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

343) 
344)   // check if current call
345)   bool current = data->call == call;
346) 
347)   // check DTMF
348)   char c;
349)   if (dtmf >= '0' && dtmf <= '9') {
350)     c = dtmf;
351)   } else if (dtmf == '*') {
352)     c = '*';
353)   } else if (dtmf == '#') {
354)     c = '#';
355)   } else {
356)     c = '?';
357)   }
358) 
359)   std::stringstream line;
360)   line << "dtmf received " << (current ? "(current call)" : "(other call)")
361)        << ": " << c;
362)   log(*data, line.str());
363) 
364)   // ignore DTMF from other calls
365)   if (! current) {
366)     return;
367)   }
368) 
369)   // report DTMF keys
370)   {
371)     std::lock_guard<std::mutex> lock(data->sharedData->mtx);
372)     data->sharedData->dtmf += c;
373)   }
374) }
375) 
376) /**
377)  * @brief register if not active and login data available
378)  * @param[in,out] data data of SIP client
379)  * @param[in] server SIP server
380)  * @param[in] username SIP username
381)  * @param[in] password SIP password
382)  */
383) void do_register(Data &data, std::string const &server,
384)                  std::string const &username, std::string &password)
385) {
386)   if (data.lc) {
387)     return;
388)   }
389)   if (server.empty()) {
390)     return;
391)   }
392) 
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

393)   LinphoneFactory *factory = linphone_factory_get();
394) 
395)   // create linphone callback object
396)   data.callbacks = linphone_factory_create_core_cbs(factory);
397)   if (! data.callbacks) {
398)     log(data, "failed to create linphone callback object");
399)     return;
400)   }
401) 
402)   // set callbacks
403)   linphone_core_cbs_set_global_state_changed(data.callbacks,
404)                                              global_state_changed);
405)   linphone_core_cbs_set_registration_state_changed(data.callbacks,
406)                                                    registration_state_changed);
407)   linphone_core_cbs_set_call_state_changed(data.callbacks, call_state_changed);
408)   linphone_core_cbs_set_dtmf_received(data.callbacks, dtmf_received);
409) 
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

410)   // create linphone core object
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

411)   data.lc = linphone_factory_create_core(factory, data.callbacks, NULL, NULL);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

412)   if (! data.lc) {
413)     log(data, "failed to create linphone core");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

414)     linphone_core_cbs_unref(data.callbacks);
415)     data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

416)     return;
417)   }
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

418)   linphone_core_set_user_data(data.lc, &data);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

419)   log(data, "linphone core created");
420) 
Stefan Schuermans randomize SIP ports for mul...

Stefan Schuermans authored 5 years ago

421)   // set ports to random (to allow multiple SIP endpoints)
422)   LinphoneTransports *transports = linphone_factory_create_transports(factory);
423)   if (transports != nullptr) {
424)     linphone_transports_set_udp_port(transports, LC_SIP_TRANSPORT_RANDOM);
425)     linphone_transports_set_tcp_port(transports, LC_SIP_TRANSPORT_RANDOM);
426)     linphone_transports_set_tls_port(transports, LC_SIP_TRANSPORT_RANDOM);
427)     linphone_transports_set_dtls_port(transports, LC_SIP_TRANSPORT_RANDOM);
428)     linphone_core_set_transports(data.lc, transports);
429)     linphone_transports_unref(transports);
430)     log(data, "linphone core: transports set to random");
431)   } else {
432)     log(data, "linphone core: cannot set transports");
433)   }
434) 
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

435)   // set auth data
436)   if (! username.empty() && ! password.empty()) {
437)     LinphoneAuthInfo *auth_info =
438)         linphone_auth_info_new(username.c_str(), username.c_str(),
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

439)                                password.c_str(), nullptr, "", "");
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

440)     if (! auth_info) {
441)       log(data, "failed to create auth info");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

442)       linphone_core_unref(data.lc);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

443)       data.lc = nullptr;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

444)       linphone_core_cbs_unref(data.callbacks);
445)       data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

446)       return;
447)     }
448)     linphone_core_add_auth_info(data.lc, auth_info);
449)     log(data, "auth info set");
450)   } else {
451)     log(data, "no auth data available");
452)   }
453) 
454)   // configure proxy
455)   std::string sipserver = "sip:" + server;
456)   std::string identity = "sip:" + username + "@" + server;
457)   LinphoneProxyConfig *proxy = linphone_core_create_proxy_config(data.lc);
458)   if (! proxy) {
459)     log(data, "failed to create proxy config");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

460)     linphone_core_unref(data.lc);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

461)     data.lc = nullptr;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

462)     linphone_core_cbs_unref(data.callbacks);
463)     data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

464)     return;
465)   }
466)   linphone_proxy_config_set_server_addr(proxy, sipserver.c_str());
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

467)   LinphoneAddress *addr =
468)       linphone_proxy_config_normalize_sip_uri(proxy, identity.c_str());
469)   if (addr != NULL) {
470)     linphone_proxy_config_set_identity_address(proxy, addr);
471)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

472)   linphone_proxy_config_enable_register(proxy, TRUE);
473)   linphone_core_add_proxy_config(data.lc, proxy);
474)   log(data, "proxy config set");
475) 
476)   // tell linphone not to rind and to use files instead of sound card
477)   linphone_core_set_ring(data.lc, nullptr);
478)   linphone_core_use_files(data.lc, TRUE);
479)   linphone_core_set_play_file(data.lc, nullptr);
480) }
481) 
482) /**
483)  * @brief deregister if active
484)  * @param[in,out] data data of SIP client
485)  */
486) void do_deregister(Data &data)
487) {
488)   if (! data.lc) {
489)     return;
490)   }
491) 
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

492)   log(data, "unreferencing...");
493)   linphone_core_unref(data.lc);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

494)   data.lc = nullptr;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

495)   linphone_core_cbs_unref(data.callbacks);
496)   data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

497)   data.call = nullptr;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

498)   log(data, "unreferenced");
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

499) }
500) 
501) /**
502)  * @brief play sound on call if active
503)  * @param[in,out] data data of SIP client
504)  * @param[in] name name of sound
505)  */
506) void do_play(Data &data, std::string const &name)
507) {
508)   if (! data.lc) {
509)     return;
510)   }
511)   if (! data.call) {
512)     return;
513)   }
514) 
515)   std::stringstream line;
516)   line << "playing sound \"" << name << "\"";
517)   log(data, line.str());
518)   set_playback(data, name);
519)   start_playback(data);
520) }
521) 
522) /**
523)  * @brief hangup call if active
524)  * @param[in,out] data data of SIP client
525)  */
526) void do_hangup(Data &data)
527) {
528)   if (! data.lc) {
529)     return;
530)   }
531)   if (! data.call) {
532)     return;
533)   }
534) 
535)   log(data, "terminating call...");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

536)   linphone_call_terminate(data.call);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

537)   data.call = nullptr;
538)   log(data, "call terminated");
539) }
540) 
541) /**
542)  * @brief linphone worker thread
543)  * @param[in] soundDir directory of sound files
544)  * @param[in,out] data shared data for communication with main Blinker thread
545)  */
546) void worker(SipPhone::ConfigData const &configData,
547)             SipPhone::SharedData &sharedData)
548) {
549)   // set up data of SIP client
550)   Data data;
551)   data.configData = &configData;
552)   data.sharedData = &sharedData;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

553)   data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

554)   data.lc = nullptr;
555)   data.call = nullptr;
556)   data.logLineCnt = 0;
557) 
558)   // main loop of worker - with shared data locked
559)   std::chrono::milliseconds timeout(10);
560)   std::unique_lock<std::mutex> lock(sharedData.mtx);
561)   while (sharedData.run) {
562) 
563)     // hangup
564)     if (sharedData.hangup) {
565)       sharedData.hangup = false;
566)       sharedData.reqPlay = false;
567)       sharedData.dtmf.clear();
568)       sharedData.terminated = true;
569)       // execute hangup with unlocked shared data (parallelism!)
570)       lock.unlock();
571)       do_hangup(data);
572)       lock.lock();
573)       continue; // re-check everything after re-locking mutex
574)     }
575) 
576)     // re-register (including initial registration and derigstration)
577)     if (sharedData.reregister) {
578)       sharedData.reregister = false;
579)       sharedData.hangup = false;
580)       sharedData.reqPlay = false;
581)       sharedData.dtmf.clear();
582)       sharedData.terminated = true;
583)       std::string server = sharedData.server;
584)       std::string username = sharedData.username;
585)       std::string password = sharedData.password;
586)       // execute re-registration with unlocked shared data (parallelism!)
587)       lock.unlock();
588)       do_deregister(data);
589)       do_register(data, server, username, password);
590)       lock.lock();
591)       continue; // re-check everything after re-locking mutex
592)     }
593) 
594)     // play sound
595)     if (sharedData.reqPlay) {
596)       sharedData.reqPlay = false;
597)       std::string name = sharedData.reqPlayName;
598)       // execute hangup with unlocked shared data (parallelism!)
599)       lock.unlock();
600)       do_play(data, name);
601)       lock.lock();
602)       continue; // re-check everything after re-locking mutex
603)     }
604) 
605)     // background processing by linphone if active
606)     if (data.lc) {
607)       lock.unlock();
608)       linphone_core_iterate(data.lc);
609)       lock.lock();
610)     }
611) 
612)     // nothing to do, wait for signal
613)     sharedData.cond.wait_for(lock, timeout);
614) 
615)   } // while (sharedData.run)
616) }
617) 
618) } // namespace linphone
619) 
620) #endif // #ifdef BLINKER_CFG_LINPHONE
621) 
622) /**
623)  * @brief global initialization (call once before using this class)
624)  * @param[in] globalLogDir directory for global SIP log files
625)  */
626) void SipPhone::init(const Directory &globalLogDir)
627) {
628) #ifdef BLINKER_CFG_LINPHONE
629)   linphone::init(globalLogDir.getFile("sip.log").getPath());
630) #endif
631) }
632) 
633) /**
634)  * @brief constructor
635)  * @param[in] name module name
636)  * @param[in] mgrs managers
637)  * @param[in] dirBase base directory
638)  */
639) SipPhone::SipPhone(const std::string &name, Mgrs &mgrs,
640)                    const Directory &dirBase):
641)   Module(name, mgrs, dirBase),
642)   m_fileServer(dirBase.getFile("server")),
643)   m_fileUsername(dirBase.getFile("username")),
644)   m_filePassword(dirBase.getFile("password")),
645)   m_fileTarget(dirBase.getFile("target")),
646)   m_configData(),
647)   m_worker(),
648)   m_sharedData(),
649)   m_curConn(nullptr)
650) {
651)   m_configData.soundDir = dirBase.getSubdir("sounds").getPath();
652)   m_configData.logFileName = dirBase.getFile("sip.log").getPath();
653)   m_sharedData.run = true;
654)   m_sharedData.reregister = false;
655)   m_sharedData.reqPlay = false;
656)   m_sharedData.hangup = false;
657)   m_sharedData.accepted = false;
658)   m_sharedData.terminated = false;
659) 
660)   m_mgrs.m_callMgr.requestTimeCall(this, Time::now());
661) 
662) #ifdef BLINKER_CFG_LINPHONE
663)   m_worker = std::thread(linphone::worker, std::ref(m_configData),
664)                          std::ref(m_sharedData));
665) #endif
666) 
667)   sipRegister();
668) }
669) 
670) /// virtual destructor
671) SipPhone::~SipPhone()
672) {
673)   if (m_curConn) {
674)     m_curConn->close();
675)     m_curConn = nullptr;
676)   }
677) 
678)   sipDeregister();
679) 
680)   {
681)     std::lock_guard<std::mutex> lock(m_sharedData.mtx);
682)     m_sharedData.run = false;
683)   }
684)   m_sharedData.cond.notify_one();
685) #ifdef BLINKER_CFG_LINPHONE
686)   m_worker.join();
687) #endif
688) 
689)   m_mgrs.m_callMgr.cancelTimeCall(this);
690) }
691) 
692) /// check for update of configuration
693) void SipPhone::updateConfig()
694) {
695)   // server, username or password file modified -> re-connect
696)   if (m_fileServer.checkModified() || m_fileUsername.checkModified() ||
697)                                       m_filePassword.checkModified()) {
698)     // re-register
699)     sipDeregister();
700)     sipRegister();
701)   }
702) 
703)   // target file was modified -> re-get target operator interface to connect to
704)   if (m_fileTarget.checkModified()) {
705)     m_fileTarget.update();
706)   }
707) }
708) 
709) /// callback when requested time reached
710) void SipPhone::timeCall()
711) {
712)   Time now = Time::now();
713) 
714)   // get information from SIP phone worker
715)   bool accepted;
716)   std::string dtmf;
717)   bool terminated;
718)   {
719)     std::lock_guard<std::mutex> lock(m_sharedData.mtx);
720)     accepted = m_sharedData.accepted;
721)     m_sharedData.accepted = false;
722)     dtmf = m_sharedData.dtmf;
723)     m_sharedData.dtmf.clear();
724)     terminated = m_sharedData.terminated;
725)     m_sharedData.terminated = false;
726)   }
727) 
728)   // phone call has terminated or new one has been accepted
729)   if (terminated || accepted) {
730)     // close connection if any
731)     if (m_curConn) {
732)       // request hang up of phone
733)       {
734)         std::lock_guard<std::mutex> lock(m_sharedData.mtx);
735)         m_sharedData.hangup = true;
736)       }
737)       // close and forget connection
738)       m_curConn->close();
739)       m_curConn = nullptr;
740)     }
741)   }
742) 
743)   // phone call has been accepted
744)   if (accepted) {
745)     // try to open new connection to target operator interface
746)     if (m_fileTarget.m_valid) {
747)       m_curConn = m_mgrs.m_opMgr.connect(m_fileTarget.m_obj.m_str, this);
748)     }
Stefan Schuermans sip: hang up after connect...

Stefan Schuermans authored 5 years ago

749)     // operator connection failed -> request hang up of phone
750)     if (! m_curConn) {
751)       std::lock_guard<std::mutex> lock(m_sharedData.mtx);
752)       m_sharedData.hangup = true;
753)     }