24c542a604919a1997293ace23b00a6101f4bcf8
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,
Stefan Schuermans fix liblinphone threading i...

Stefan Schuermans authored 5 years ago

37)  * because some calls to linphone take long (up to two seconds)
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

38)  */
39) namespace linphone {
40) 
Stefan Schuermans fix liblinphone threading i...

Stefan Schuermans authored 5 years ago

41) /// interlock for liblinphone, higher in mutex hierarchy than shared data mutex
42) static std::mutex g_mtx;
43) 
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

44) static char const *loglevel2str(OrtpLogLevel lev)
45) {
46)   switch(lev) {
47)   case ORTP_DEBUG: return "DEBUG";
48)   case ORTP_MESSAGE: return "MESSAGE";
49)   case ORTP_WARNING: return "WARNING";
50)   case ORTP_ERROR: return "ERROR";
51)   case ORTP_FATAL: return "FATAL";
52)   case ORTP_TRACE: return "TRACE";
53)   case ORTP_LOGLEV_END: return "LOGLEV_END";
54)   default: return "?";
55)   }
56) }
57) 
58) static char const *gstate2str(LinphoneGlobalState gstate)
59) {
60)   switch (gstate) {
61)   case LinphoneGlobalOff: return "Off";
62)   case LinphoneGlobalStartup: return "Startup";
63)   case LinphoneGlobalOn: return "On";
64)   case LinphoneGlobalShutdown: return "Shutdown";
65)   default: return "?";
66)   }
67) }
68) 
69) static char const *rstate2str(LinphoneRegistrationState rstate)
70) {
71)   switch (rstate) {
72)   case LinphoneRegistrationNone: return "None";
73)   case LinphoneRegistrationProgress: return "Progress";
74)   case LinphoneRegistrationOk: return "Ok";
75)   case LinphoneRegistrationCleared: return "Cleared";
76)   case LinphoneRegistrationFailed: return "Failed";
77)   default: return "?";
78)   }
79) }
80) 
81) static char const *cstate2str(LinphoneCallState cstate)
82) {
83)   switch (cstate) {
84)   case LinphoneCallIdle: return "Idle";
85)   case LinphoneCallIncomingReceived: return "IncomingReceived";
86)   case LinphoneCallOutgoingInit: return "OutgoingInit";
87)   case LinphoneCallOutgoingProgress: return "OutgoingProgress";
88)   case LinphoneCallOutgoingRinging: return "OutgoingRinging";
89)   case LinphoneCallOutgoingEarlyMedia: return "OutgoingEarlyMedia";
90)   case LinphoneCallConnected: return "Connected";
91)   case LinphoneCallStreamsRunning: return "StreamsRunning";
92)   case LinphoneCallPausing: return "Pausing";
93)   case LinphoneCallPaused: return "Paused";
94)   case LinphoneCallResuming: return "Resuming";
95)   case LinphoneCallRefered: return "Refered";
96)   case LinphoneCallError: return "Error";
97)   case LinphoneCallEnd: return "End";
98)   case LinphoneCallPausedByRemote: return "PausedByRemote";
99)   case LinphoneCallUpdatedByRemote: return "UpdatedByRemote";
100)   case LinphoneCallIncomingEarlyMedia: return "IncomingEarlyMedia";
101)   case LinphoneCallUpdating: return "Updating";
102)   case LinphoneCallReleased: return "Released";
103)   default: return "?";
104)   }
105) }
106) 
107) std::string glLogFileName; ///< name of global log file
108) std::ofstream glLogStream; ///< stream to open global log file
109) unsigned int glLogLineCnt; ///< number of lines already logged
110) 
111) /**
112)  * @brief log information from linphone library
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

147)   (void)domain;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

163)   LinphoneCore *lc; ///< linphone core object, if active
164)   LinphoneCall *call; ///< current call, if available
165)   std::string playback; ///< name of playback file
166)   std::ofstream logStream; ///< stream to open log file
167)   unsigned int logLineCnt; ///< number of lines already logged to file
168) };
169) 
170) /**
Stefan Schuermans fix liblinphone threading i...

Stefan Schuermans authored 5 years ago

171)  * @brief set playback file
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

172)  * @param[in,out] data data of SIP client
173)  * @param[in] name name of sound file (without extension)
174)  */
175) void set_playback(Data &data, std::string const &name)
176) {
177)   Directory dir(data.configData->soundDir);
178)   data.playback = dir.getFile(name + ".wav").getPath();
179) }
180) 
Stefan Schuermans fix comments

Stefan Schuermans authored 5 years ago

181) /**
182)  * @brief start playback of sound
183)  * @param[in,out] data data of SIP client
184)  */
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

185) void start_playback(Data &data)
186) {
187)   if (data.lc && ! data.playback.empty()) {
188)     linphone_core_set_play_file(data.lc, data.playback.c_str());
189)   }
190) }
191) 
192) /**
193)  * @brief write log message
194)  * @param[in,out] data data of SIP client
195)  * @param[in] line lie to log
196)  */
197) void log(Data &data, std::string const &line)
198) {
199)   // (re-)open logfile on first line
200)   if (data.logLineCnt == 0) {
201)     // close old file and clean up (just to be on the safe side)
202)     data.logStream.close();
203)     data.logStream.clear();
204)     // keep previous log file
205)     rename(data.configData->logFileName.c_str(),
206)            (data.configData->logFileName + ".prev").c_str());
207)     // open new file
208)     data.logStream.open(data.configData->logFileName.c_str(), std::ios::out);
209)   }
210)   // write log line
211)   data.logStream << Time::now().toStr() << " " << line << std::endl;
212)   // count lines
213)   ++data.logLineCnt;
214)   // close file if maximum line count reached
215)   if (data.logLineCnt >= 10000) {
216)     // close old file and clean up
217)     data.logStream.close();
218)     data.logStream.clear();
219)     // reset line count, so new file is opened on next line
220)     data.logLineCnt = 0;
221)   }
222) }
223) 
224) /**
225)  * @brief global SIP state changed
226)  * @param[in] lc linphone core object
227)  * @param[in] gstate new global SIP state
228)  * @param[in] message informational message
229)  */
230) void global_state_changed(struct _LinphoneCore *lc,
231)                           LinphoneGlobalState gstate,
232)                           const char *message)
233) {
234)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

235)   if (data == nullptr) {
236)     return; // still initializing -> ignore
237)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

257)   if (data == nullptr) {
258)     return; // still initializing -> ignore
259)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

279)   if (data == nullptr) {
280)     return; // still initializing -> ignore
281)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

314)       break;
315)     default:
316)       break;
317)     }
318)   }
319)   // no call active -> accept call
320)   else {
321)     switch (cstate) {
322)     case LinphoneCallIncomingReceived:
323)       data->call = call;
324)       {
325)         std::lock_guard<std::mutex> lock(data->sharedData->mtx);
326)         data->sharedData->accepted = true;
327)       }
328)       data->playback.clear();
329)       log(*data, "accepting call");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

330)       linphone_call_accept(call);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

331)       break;
332)     default:
333)       break;
334)     }
335)   }
336) }
337) 
338) /**
339)  * @brief DTMF received
340)  * @param[in] lc linphone core object
341)  * @param[in] call call object
342)  * @param[in] dtmf DTMF as ASCII character
343)  */
344) void dtmf_received(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf)
345) {
346)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

347)   if (data == nullptr) {
348)     return; // still initializing -> ignore
349)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

400)   LinphoneFactory *factory = linphone_factory_get();
401) 
402)   // create linphone callback object
403)   data.callbacks = linphone_factory_create_core_cbs(factory);
404)   if (! data.callbacks) {
405)     log(data, "failed to create linphone callback object");
406)     return;
407)   }
408) 
409)   // set callbacks
410)   linphone_core_cbs_set_global_state_changed(data.callbacks,
411)                                              global_state_changed);
412)   linphone_core_cbs_set_registration_state_changed(data.callbacks,
413)                                                    registration_state_changed);
414)   linphone_core_cbs_set_call_state_changed(data.callbacks, call_state_changed);
415)   linphone_core_cbs_set_dtmf_received(data.callbacks, dtmf_received);
416) 
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

421)     linphone_core_cbs_unref(data.callbacks);
422)     data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

423)     return;
424)   }
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

428)   // set ports to random (to allow multiple SIP endpoints)
429)   LinphoneTransports *transports = linphone_factory_create_transports(factory);
430)   if (transports != nullptr) {
431)     linphone_transports_set_udp_port(transports, LC_SIP_TRANSPORT_RANDOM);
432)     linphone_transports_set_tcp_port(transports, LC_SIP_TRANSPORT_RANDOM);
433)     linphone_transports_set_tls_port(transports, LC_SIP_TRANSPORT_RANDOM);
434)     linphone_transports_set_dtls_port(transports, LC_SIP_TRANSPORT_RANDOM);
435)     linphone_core_set_transports(data.lc, transports);
436)     linphone_transports_unref(transports);
437)     log(data, "linphone core: transports set to random");
438)   } else {
439)     log(data, "linphone core: cannot set transports");
440)   }
441) 
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

442)   // set auth data
443)   if (! username.empty() && ! password.empty()) {
444)     LinphoneAuthInfo *auth_info =
445)         linphone_auth_info_new(username.c_str(), username.c_str(),
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

451)       linphone_core_cbs_unref(data.callbacks);
452)       data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

453)       return;
454)     }
455)     linphone_core_add_auth_info(data.lc, auth_info);
456)     log(data, "auth info set");
457)   } else {
458)     log(data, "no auth data available");
459)   }
460) 
461)   // configure proxy
462)   std::string sipserver = "sip:" + server;
463)   std::string identity = "sip:" + username + "@" + server;
464)   LinphoneProxyConfig *proxy = linphone_core_create_proxy_config(data.lc);
465)   if (! proxy) {
466)     log(data, "failed to create proxy config");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

469)     linphone_core_cbs_unref(data.callbacks);
470)     data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

471)     return;
472)   }
473)   linphone_proxy_config_set_server_addr(proxy, sipserver.c_str());
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

474)   LinphoneAddress *addr =
475)       linphone_proxy_config_normalize_sip_uri(proxy, identity.c_str());
476)   if (addr != NULL) {
477)     linphone_proxy_config_set_identity_address(proxy, addr);
478)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

499)   log(data, "unreferencing...");
500)   linphone_core_unref(data.lc);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

502)   linphone_core_cbs_unref(data.callbacks);
503)   data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

544)   data.call = nullptr;
545)   log(data, "call terminated");
546) }
547) 
548) /**
549)  * @brief linphone worker thread
Stefan Schuermans fix comments

Stefan Schuermans authored 5 years ago

550)  * @param[in] configData configuration data
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

551)  * @param[in,out] data shared data for communication with main Blinker thread
552)  */
553) void worker(SipPhone::ConfigData const &configData,
554)             SipPhone::SharedData &sharedData)
555) {
556)   // set up data of SIP client
557)   Data data;
558)   data.configData = &configData;
559)   data.sharedData = &sharedData;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

561)   data.lc = nullptr;
562)   data.call = nullptr;
563)   data.logLineCnt = 0;
564) 
565)   // main loop of worker - with shared data locked
566)   std::chrono::milliseconds timeout(10);
Stefan Schuermans fix liblinphone threading i...

Stefan Schuermans authored 5 years ago

567)   std::unique_lock<std::mutex> g_lock(g_mtx);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

568)   std::unique_lock<std::mutex> lock(sharedData.mtx);
569)   while (sharedData.run) {
570) 
571)     // hangup
572)     if (sharedData.hangup) {
573)       sharedData.hangup = false;
574)       sharedData.reqPlay = false;
575)       sharedData.dtmf.clear();
576)       sharedData.terminated = true;
577)       // execute hangup with unlocked shared data (parallelism!)
578)       lock.unlock();
579)       do_hangup(data);
580)       lock.lock();
581)       continue; // re-check everything after re-locking mutex
582)     }
583) 
584)     // re-register (including initial registration and derigstration)
585)     if (sharedData.reregister) {
586)       sharedData.reregister = false;
587)       sharedData.hangup = false;
588)       sharedData.reqPlay = false;
589)       sharedData.dtmf.clear();
590)       sharedData.terminated = true;
591)       std::string server = sharedData.server;
592)       std::string username = sharedData.username;
593)       std::string password = sharedData.password;
594)       // execute re-registration with unlocked shared data (parallelism!)
595)       lock.unlock();
596)       do_deregister(data);
597)       do_register(data, server, username, password);
598)       lock.lock();
599)       continue; // re-check everything after re-locking mutex
600)     }
601) 
602)     // play sound
603)     if (sharedData.reqPlay) {
604)       sharedData.reqPlay = false;
605)       std::string name = sharedData.reqPlayName;
606)       // execute hangup with unlocked shared data (parallelism!)
607)       lock.unlock();
608)       do_play(data, name);
609)       lock.lock();
610)       continue; // re-check everything after re-locking mutex
611)     }
612) 
613)     // background processing by linphone if active
614)     if (data.lc) {
615)       lock.unlock();
616)       linphone_core_iterate(data.lc);
617)       lock.lock();
618)     }
619) 
Stefan Schuermans fix liblinphone threading i...

Stefan Schuermans authored 5 years ago

620)     // nothing to do, wait for signal (with both locks released)
621)     lock.unlock();
622)     sharedData.cond.wait_for(g_lock, timeout);
623)     lock.lock();
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

624) 
625)   } // while (sharedData.run)
626) }
627) 
628) } // namespace linphone
629) 
630) #endif // #ifdef BLINKER_CFG_LINPHONE
631) 
632) /**
633)  * @brief global initialization (call once before using this class)
634)  * @param[in] globalLogDir directory for global SIP log files
635)  */
636) void SipPhone::init(const Directory &globalLogDir)
637) {
638) #ifdef BLINKER_CFG_LINPHONE
639)   linphone::init(globalLogDir.getFile("sip.log").getPath());
640) #endif
641) }
642) 
643) /**
644)  * @brief constructor
645)  * @param[in] name module name
646)  * @param[in] mgrs managers
647)  * @param[in] dirBase base directory
648)  */
649) SipPhone::SipPhone(const std::string &name, Mgrs &mgrs,
650)                    const Directory &dirBase):
651)   Module(name, mgrs, dirBase),
652)   m_fileServer(dirBase.getFile("server")),
653)   m_fileUsername(dirBase.getFile("username")),
654)   m_filePassword(dirBase.getFile("password")),
655)   m_fileTarget(dirBase.getFile("target")),
656)   m_configData(),
657)   m_worker(),
658)   m_sharedData(),
659)   m_curConn(nullptr)
660) {
661)   m_configData.soundDir = dirBase.getSubdir("sounds").getPath();
662)   m_configData.logFileName = dirBase.getFile("sip.log").getPath();
663)   m_sharedData.run = true;
664)   m_sharedData.reregister = false;
665)   m_sharedData.reqPlay = false;
666)   m_sharedData.hangup = false;
667)   m_sharedData.accepted = false;
668)   m_sharedData.terminated = false;
669) 
670)   m_mgrs.m_callMgr.requestTimeCall(this, Time::now());
671) 
672) #ifdef BLINKER_CFG_LINPHONE
673)   m_worker = std::thread(linphone::worker, std::ref(m_configData),
674)                          std::ref(m_sharedData));
675) #endif
676) 
677)   sipRegister();
678) }
679) 
680) /// virtual destructor
681) SipPhone::~SipPhone()
682) {
683)   if (m_curConn) {
684)     m_curConn->close();
685)     m_curConn = nullptr;
686)   }
687) 
688)   sipDeregister();
689) 
690)   {
691)     std::lock_guard<std::mutex> lock(m_sharedData.mtx);
692)     m_sharedData.run = false;
693)   }
694)   m_sharedData.cond.notify_one();
695) #ifdef BLINKER_CFG_LINPHONE
696)   m_worker.join();
697) #endif
698) 
699)   m_mgrs.m_callMgr.cancelTimeCall(this);
700) }
701) 
702) /// check for update of configuration
703) void SipPhone::updateConfig()
704) {
705)   // server, username or password file modified -> re-connect
706)   if (m_fileServer.checkModified() || m_fileUsername.checkModified() ||
707)                                       m_filePassword.checkModified()) {
708)     // re-register
709)     sipDeregister();
710)     sipRegister();
711)   }
712) 
713)   // target file was modified -> re-get target operator interface to connect to
714)   if (m_fileTarget.checkModified()) {
715)     m_fileTarget.update();
716)   }
717) }
718) 
719) /// callback when requested time reached
720) void SipPhone::timeCall()
721) {
722)   Time now = Time::now();
723) 
724)   // get information from SIP phone worker
725)   bool accepted;
726)   std::string dtmf;
727)   bool terminated;
728)   {
729)     std::lock_guard<std::mutex> lock(m_sharedData.mtx);
730)     accepted = m_sharedData.accepted;
731)     m_sharedData.accepted = false;
732)     dtmf = m_sharedData.dtmf;
733)     m_sharedData.dtmf.clear();
734)     terminated = m_sharedData.terminated;
735)     m_sharedData.terminated = false;
736)   }
737) 
738)   // phone call has terminated or new one has been accepted
739)   if (terminated || accepted) {
740)     // close connection if any
741)     if (m_curConn) {
742)       // request hang up of phone
743)       {
744)         std::lock_guard<std::mutex> lock(m_sharedData.mtx);
745)         m_sharedData.hangup = true;
746)       }
747)       // close and forget connection
748)       m_curConn->close();
749)       m_curConn = nullptr;
750)     }
751)   }
752) 
753)   // phone call has been accepted
754)   if (accepted) {
755)     // try to open new connection to target operator interface
756)     if (m_fileTarget.m_valid) {
757)       m_curConn = m_mgrs.m_opMgr.connect(m_fileTarget.m_obj.m_str, this);
758)     }
Stefan Schuermans sip: hang up after connect...

Stefan Schuermans authored 5 years ago

759)     // operator connection failed -> request hang up of phone
760)     if (! m_curConn) {
761)       std::lock_guard<std::mutex> lock(m_sharedData.mtx);
762)       m_sharedData.hangup = true;
763)     }