b052c7d6f85822c63cb294d661b339c271e059b2
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 <stdio.h>
12) #include <string>
13) #include <string.h>
14) #include <thread>
Stefan Schuermans implement common sound dir,...

Stefan Schuermans authored 5 years ago

15) #include <vector>
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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 adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

44) static char const *loglevel2str(LinphoneLogLevel lev)
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

45) {
46)   switch(lev) {
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

47)   case LinphoneLogLevelDebug: return "DEBUG";
48)   case LinphoneLogLevelTrace: return "TRACE";
49)   case LinphoneLogLevelMessage: return "MESSAGE";
50)   case LinphoneLogLevelWarning: return "WARNING";
51)   case LinphoneLogLevelError: return "ERROR";
52)   case LinphoneLogLevelFatal: return "FATAL";
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

53)   default: return "?";
54)   }
55) }
56) 
57) static char const *gstate2str(LinphoneGlobalState gstate)
58) {
59)   switch (gstate) {
60)   case LinphoneGlobalOff: return "Off";
61)   case LinphoneGlobalStartup: return "Startup";
62)   case LinphoneGlobalOn: return "On";
63)   case LinphoneGlobalShutdown: return "Shutdown";
64)   default: return "?";
65)   }
66) }
67) 
68) static char const *rstate2str(LinphoneRegistrationState rstate)
69) {
70)   switch (rstate) {
71)   case LinphoneRegistrationNone: return "None";
72)   case LinphoneRegistrationProgress: return "Progress";
73)   case LinphoneRegistrationOk: return "Ok";
74)   case LinphoneRegistrationCleared: return "Cleared";
75)   case LinphoneRegistrationFailed: return "Failed";
76)   default: return "?";
77)   }
78) }
79) 
80) static char const *cstate2str(LinphoneCallState cstate)
81) {
82)   switch (cstate) {
83)   case LinphoneCallIdle: return "Idle";
84)   case LinphoneCallIncomingReceived: return "IncomingReceived";
85)   case LinphoneCallOutgoingInit: return "OutgoingInit";
86)   case LinphoneCallOutgoingProgress: return "OutgoingProgress";
87)   case LinphoneCallOutgoingRinging: return "OutgoingRinging";
88)   case LinphoneCallOutgoingEarlyMedia: return "OutgoingEarlyMedia";
89)   case LinphoneCallConnected: return "Connected";
90)   case LinphoneCallStreamsRunning: return "StreamsRunning";
91)   case LinphoneCallPausing: return "Pausing";
92)   case LinphoneCallPaused: return "Paused";
93)   case LinphoneCallResuming: return "Resuming";
94)   case LinphoneCallRefered: return "Refered";
95)   case LinphoneCallError: return "Error";
96)   case LinphoneCallEnd: return "End";
97)   case LinphoneCallPausedByRemote: return "PausedByRemote";
98)   case LinphoneCallUpdatedByRemote: return "UpdatedByRemote";
99)   case LinphoneCallIncomingEarlyMedia: return "IncomingEarlyMedia";
100)   case LinphoneCallUpdating: return "Updating";
101)   case LinphoneCallReleased: return "Released";
102)   default: return "?";
103)   }
104) }
105) 
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

106) LinphoneLoggingService *glLogSrv; ///< logging service
107) LinphoneLoggingServiceCbs *glLogCbs; ///< logging callbacks
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

108) std::string glLogFileName; ///< name of global log file
109) std::ofstream glLogStream; ///< stream to open global log file
110) unsigned int glLogLineCnt; ///< number of lines already logged
111) 
112) /**
113)  * @brief log information from linphone library
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

114)  * @param[in] log_srv logging service - ignored
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

116)  * @param[in] lev log level
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

117)  * @param[in] msg message string
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

118)  */
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

119) static void log_msg_wr(LinphoneLoggingService *log_srv, const char *domain,
120)                        LinphoneLogLevel lev, const char *msg)
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

121) {
122)   // (re-)open logfile on first line
123)   if (glLogLineCnt == 0) {
124)     // close old file and clean up (just to be on the safe side)
125)     glLogStream.close();
126)     glLogStream.clear();
127)     // keep previous log file
128)     rename(glLogFileName.c_str(), (glLogFileName + ".prev").c_str());
129)     // open new file
130)     glLogStream.open(glLogFileName.c_str(), std::ios::out);
131)   }
132)   // write log line
133)   glLogStream << Time::now().toStr() << " "
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

134)               << loglevel2str(lev) << " " << msg << std::endl;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

135)   // count lines
136)   ++glLogLineCnt;
137)   // close file if maximum line count reached
138)   if (glLogLineCnt >= 10000) {
139)     // close old file and clean up
140)     glLogStream.close();
141)     glLogStream.clear();
142)     // reset line count, so new file is opened on next line
143)     glLogLineCnt = 0;
144)   }
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

145)   (void)log_srv;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

146)   (void)domain;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

147) }
148) 
149) /// global init
150) void init(std::string const &logFileName)
151) {
152)   glLogFileName = logFileName;
153)   glLogLineCnt = 0;
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

154)   glLogSrv = linphone_logging_service_get();
155)   linphone_logging_service_ref(glLogSrv);
156)   LinphoneFactory *factory = linphone_factory_get();
157)   glLogCbs = linphone_factory_create_logging_service_cbs(factory);
158)   linphone_logging_service_cbs_set_log_message_written(glLogCbs, log_msg_wr);
159) }
160) 
161) /// global cleanup
162) void exit()
163) {
164)   linphone_logging_service_cbs_unref(glLogCbs);
165)   linphone_logging_service_unref(glLogSrv);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

166) }
167) 
168) /// data of SIP client worker thread
169) struct Data {
170)   SipPhone::ConfigData const *configData; ///< config data for worker thread
171)   SipPhone::SharedData *sharedData; ///< data shared with main Blinker thread
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

173)   LinphoneCore *lc; ///< linphone core object, if active
174)   LinphoneCall *call; ///< current call, if available
175)   std::string playback; ///< name of playback file
176)   std::ofstream logStream; ///< stream to open log file
177)   unsigned int logLineCnt; ///< number of lines already logged to file
178) };
179) 
180) /**
Stefan Schuermans fix liblinphone threading i...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

182)  * @param[in,out] data data of SIP client
183)  * @param[in] name name of sound file (without extension)
184)  */
185) void set_playback(Data &data, std::string const &name)
186) {
Stefan Schuermans implement common sound dir,...

Stefan Schuermans authored 5 years ago

187)   // search sound directories for file with mathcing name
188)   for (Directory const & soundDir : data.configData->soundDirs) {
189)     File soundFile(soundDir.getFile(name + ".wav"));
190)     if (soundFile.exists()) {
191)       data.playback = soundFile.getPath();
192)       return; // first existing file found is set for playback
193)     }
194)   }
195)   data.playback.clear(); // no file found -> no playback
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

196) }
197) 
Stefan Schuermans fix comments

Stefan Schuermans authored 5 years ago

198) /**
199)  * @brief start playback of sound
200)  * @param[in,out] data data of SIP client
201)  */
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

255) 
256)   std::stringstream line;
257)   line << "global state changed to " << gstate2str(gstate) << ": " << message;
258)   log(*data, line.str());
259) }
260) 
261) /**
262)  * @brief registration state changed
263)  * @param[in] lc linphone core object
264)  * @param[in] cfg proxy configuration
265)  * @param[in] rstate new registration state
266)  * @param[in] message informational message
267)  */
268) void registration_state_changed(struct _LinphoneCore *lc,
269)                                 LinphoneProxyConfig *cfg,
270)                                 LinphoneRegistrationState rstate,
271)                                 const char *message)
272) {
273)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

277)   (void)cfg;
278) 
279)   std::stringstream line;
280)   line << "registration state changed to " << rstate2str(rstate) << ": "
281)        << message;
282)   log(*data, line.str());
283) }
284) 
285) /**
286)  * @brief call state changed
287)  * @param[in] lc linphone core object
288)  * @param[in] call call object
289)  * @param[in] cstate new call state
290)  * @param[in] message informational message
291)  */
292) void call_state_changed(struct _LinphoneCore *lc, LinphoneCall *call,
293)                         LinphoneCallState cstate, const char *message)
294) {
295)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

296)   if (data == nullptr) {
297)     return; // still initializing -> ignore
298)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

299) 
300)   std::stringstream line;
301)   line << "call state changed to " << cstate2str(cstate) << ": "
302)        << message;
303)   log(*data, line.str());
304) 
305)   // current call -> handle state changes
306)   if (data->call == call) {
307)     switch (cstate) {
308)     case LinphoneCallStreamsRunning:
309)       start_playback(*data);
310)       break;
311)     case LinphoneCallRefered:
312)     case LinphoneCallError:
313)     case LinphoneCallEnd:
314)     case LinphoneCallReleased:
315)       data->call = nullptr;
316)       {
317)         std::lock_guard<std::mutex> lock(data->sharedData->mtx);
318)         data->sharedData->terminated = true;
319)       }
320)       break;
321)     default:
322)       break;
323)     }
324)   }
325)   // other call, but current call active -> reject call
326)   else if (data->call) {
327)     switch (cstate) {
328)     case LinphoneCallIncomingReceived:
329)       log(*data, "rejecting call (busy)");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

331)       break;
332)     default:
333)       break;
334)     }
335)   }
336)   // no call active -> accept call
337)   else {
338)     switch (cstate) {
339)     case LinphoneCallIncomingReceived:
340)       data->call = call;
341)       {
342)         std::lock_guard<std::mutex> lock(data->sharedData->mtx);
343)         data->sharedData->accepted = true;
344)       }
345)       data->playback.clear();
346)       log(*data, "accepting call");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

347)       linphone_call_accept(call);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

348)       break;
349)     default:
350)       break;
351)     }
352)   }
353) }
354) 
355) /**
356)  * @brief DTMF received
357)  * @param[in] lc linphone core object
358)  * @param[in] call call object
359)  * @param[in] dtmf DTMF as ASCII character
360)  */
361) void dtmf_received(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf)
362) {
363)   Data *data = (Data*)linphone_core_get_user_data(lc);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

364)   if (data == nullptr) {
365)     return; // still initializing -> ignore
366)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

367) 
368)   // check if current call
369)   bool current = data->call == call;
370) 
371)   // check DTMF
372)   char c;
373)   if (dtmf >= '0' && dtmf <= '9') {
374)     c = dtmf;
375)   } else if (dtmf == '*') {
376)     c = '*';
377)   } else if (dtmf == '#') {
378)     c = '#';
379)   } else {
380)     c = '?';
381)   }
382) 
383)   std::stringstream line;
384)   line << "dtmf received " << (current ? "(current call)" : "(other call)")
385)        << ": " << c;
386)   log(*data, line.str());
387) 
388)   // ignore DTMF from other calls
389)   if (! current) {
390)     return;
391)   }
392) 
393)   // report DTMF keys
394)   {
395)     std::lock_guard<std::mutex> lock(data->sharedData->mtx);
396)     data->sharedData->dtmf += c;
397)   }
398) }
399) 
400) /**
401)  * @brief register if not active and login data available
402)  * @param[in,out] data data of SIP client
403)  * @param[in] server SIP server
404)  * @param[in] username SIP username
405)  * @param[in] password SIP password
406)  */
407) void do_register(Data &data, std::string const &server,
408)                  std::string const &username, std::string &password)
409) {
410)   if (data.lc) {
411)     return;
412)   }
413)   if (server.empty()) {
414)     return;
415)   }
416) 
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

417)   LinphoneFactory *factory = linphone_factory_get();
418) 
419)   // create linphone callback object
420)   data.callbacks = linphone_factory_create_core_cbs(factory);
421)   if (! data.callbacks) {
422)     log(data, "failed to create linphone callback object");
423)     return;
424)   }
425) 
426)   // set callbacks
427)   linphone_core_cbs_set_global_state_changed(data.callbacks,
428)                                              global_state_changed);
429)   linphone_core_cbs_set_registration_state_changed(data.callbacks,
430)                                                    registration_state_changed);
431)   linphone_core_cbs_set_call_state_changed(data.callbacks, call_state_changed);
432)   linphone_core_cbs_set_dtmf_received(data.callbacks, dtmf_received);
433) 
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

434)   // create linphone core object
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

435)   data.lc = linphone_factory_create_core_3(factory, NULL, NULL, NULL);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

438)     linphone_core_cbs_unref(data.callbacks);
439)     data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

440)     return;
441)   }
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

442)   linphone_core_add_callbacks(data.lc, data.callbacks);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

446)   // set ports to random (to allow multiple SIP endpoints)
447)   LinphoneTransports *transports = linphone_factory_create_transports(factory);
448)   if (transports != nullptr) {
449)     linphone_transports_set_udp_port(transports, LC_SIP_TRANSPORT_RANDOM);
450)     linphone_transports_set_tcp_port(transports, LC_SIP_TRANSPORT_RANDOM);
451)     linphone_transports_set_tls_port(transports, LC_SIP_TRANSPORT_RANDOM);
452)     linphone_transports_set_dtls_port(transports, LC_SIP_TRANSPORT_RANDOM);
453)     linphone_core_set_transports(data.lc, transports);
454)     linphone_transports_unref(transports);
455)     log(data, "linphone core: transports set to random");
456)   } else {
457)     log(data, "linphone core: cannot set transports");
458)   }
459) 
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

460)   // set auth data
461)   if (! username.empty() && ! password.empty()) {
462)     LinphoneAuthInfo *auth_info =
463)         linphone_auth_info_new(username.c_str(), username.c_str(),
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

465)     if (! auth_info) {
466)       log(data, "failed to create auth info");
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_core_add_auth_info(data.lc, auth_info);
474)     log(data, "auth info set");
475)   } else {
476)     log(data, "no auth data available");
477)   }
478) 
479)   // configure proxy
480)   std::string sipserver = "sip:" + server;
481)   std::string identity = "sip:" + username + "@" + server;
482)   LinphoneProxyConfig *proxy = linphone_core_create_proxy_config(data.lc);
483)   if (! proxy) {
484)     log(data, "failed to create proxy config");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

487)     linphone_core_cbs_unref(data.callbacks);
488)     data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

489)     return;
490)   }
491)   linphone_proxy_config_set_server_addr(proxy, sipserver.c_str());
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

492)   LinphoneAddress *addr =
493)       linphone_proxy_config_normalize_sip_uri(proxy, identity.c_str());
494)   if (addr != NULL) {
495)     linphone_proxy_config_set_identity_address(proxy, addr);
496)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

497)   linphone_proxy_config_enable_register(proxy, TRUE);
498)   linphone_core_add_proxy_config(data.lc, proxy);
499)   log(data, "proxy config set");
500) 
501)   // tell linphone not to rind and to use files instead of sound card
502)   linphone_core_set_ring(data.lc, nullptr);
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

503)   linphone_core_set_use_files(data.lc, TRUE);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

504)   linphone_core_set_play_file(data.lc, nullptr);
505) }
506) 
507) /**
508)  * @brief deregister if active
509)  * @param[in,out] data data of SIP client
510)  */
511) void do_deregister(Data &data)
512) {
513)   if (! data.lc) {
514)     return;
515)   }
516) 
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

517)   log(data, "unreferencing...");
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

518)   linphone_core_remove_callbacks(data.lc, data.callbacks);
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

521)   linphone_core_cbs_unref(data.callbacks);
522)   data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

525) }
526) 
527) /**
528)  * @brief play sound on call if active
529)  * @param[in,out] data data of SIP client
530)  * @param[in] name name of sound
531)  */
532) void do_play(Data &data, std::string const &name)
533) {
534)   if (! data.lc) {
535)     return;
536)   }
537)   if (! data.call) {
538)     return;
539)   }
540) 
541)   std::stringstream line;
542)   line << "playing sound \"" << name << "\"";
543)   log(data, line.str());
544)   set_playback(data, name);
545)   start_playback(data);
546) }
547) 
548) /**
549)  * @brief hangup call if active
550)  * @param[in,out] data data of SIP client
551)  */
552) void do_hangup(Data &data)
553) {
554)   if (! data.lc) {
555)     return;
556)   }
557)   if (! data.call) {
558)     return;
559)   }
560) 
561)   log(data, "terminating call...");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

563)   data.call = nullptr;
564)   log(data, "call terminated");
565) }
566) 
567) /**
568)  * @brief linphone worker thread
Stefan Schuermans fix comments

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

570)  * @param[in,out] data shared data for communication with main Blinker thread
571)  */
572) void worker(SipPhone::ConfigData const &configData,
573)             SipPhone::SharedData &sharedData)
574) {
575)   // set up data of SIP client
576)   Data data;
577)   data.configData = &configData;
578)   data.sharedData = &sharedData;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

580)   data.lc = nullptr;
581)   data.call = nullptr;
582)   data.logLineCnt = 0;
583) 
584)   // main loop of worker - with shared data locked
585)   std::chrono::milliseconds timeout(10);
Stefan Schuermans fix liblinphone threading i...

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

587)   std::unique_lock<std::mutex> lock(sharedData.mtx);
588)   while (sharedData.run) {
589) 
590)     // hangup
591)     if (sharedData.hangup) {
592)       sharedData.hangup = false;
593)       sharedData.reqPlay = false;
594)       sharedData.dtmf.clear();
595)       sharedData.terminated = true;
596)       // execute hangup with unlocked shared data (parallelism!)
597)       lock.unlock();
598)       do_hangup(data);
599)       lock.lock();
600)       continue; // re-check everything after re-locking mutex
601)     }
602) 
603)     // re-register (including initial registration and derigstration)
604)     if (sharedData.reregister) {
605)       sharedData.reregister = false;
606)       sharedData.hangup = false;
607)       sharedData.reqPlay = false;
608)       sharedData.dtmf.clear();
609)       sharedData.terminated = true;
610)       std::string server = sharedData.server;
611)       std::string username = sharedData.username;
612)       std::string password = sharedData.password;
613)       // execute re-registration with unlocked shared data (parallelism!)
614)       lock.unlock();
615)       do_deregister(data);
616)       do_register(data, server, username, password);
617)       lock.lock();
618)       continue; // re-check everything after re-locking mutex
619)     }
620) 
621)     // play sound
622)     if (sharedData.reqPlay) {
623)       sharedData.reqPlay = false;
624)       std::string name = sharedData.reqPlayName;
625)       // execute hangup with unlocked shared data (parallelism!)
626)       lock.unlock();
627)       do_play(data, name);
628)       lock.lock();
629)       continue; // re-check everything after re-locking mutex
630)     }
631) 
632)     // background processing by linphone if active
633)     if (data.lc) {
634)       lock.unlock();
635)       linphone_core_iterate(data.lc);
636)       lock.lock();
637)     }
638) 
Stefan Schuermans fix liblinphone threading i...

Stefan Schuermans authored 5 years ago

639)     // nothing to do, wait for signal (with both locks released)
640)     lock.unlock();
641)     sharedData.cond.wait_for(g_lock, timeout);
642)     lock.lock();
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

643) 
644)   } // while (sharedData.run)
645) }
646) 
647) } // namespace linphone
648) 
649) #endif // #ifdef BLINKER_CFG_LINPHONE
650) 
651) /**
652)  * @brief global initialization (call once before using this class)
653)  * @param[in] globalLogDir directory for global SIP log files
654)  */
655) void SipPhone::init(const Directory &globalLogDir)
656) {
657) #ifdef BLINKER_CFG_LINPHONE
658)   linphone::init(globalLogDir.getFile("sip.log").getPath());
659) #endif
660) }
661) 
Stefan Schuermans adapt to liblinphone 5

Stefan Schuermans authored 1 year ago

662) /**
663)  * @brief global cleanup (call once after finishing using this class)
664)  */
665) void SipPhone::exit()
666) {
667) #ifdef BLINKER_CFG_LINPHONE
668)   linphone::exit();
669) #endif
670) }
671) 
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

672) /**
673)  * @brief constructor
674)  * @param[in] name module name
675)  * @param[in] mgrs managers
676)  * @param[in] dirBase base directory
677)  */
678) SipPhone::SipPhone(const std::string &name, Mgrs &mgrs,
679)                    const Directory &dirBase):
680)   Module(name, mgrs, dirBase),
681)   m_fileServer(dirBase.getFile("server")),
682)   m_fileUsername(dirBase.getFile("username")),
683)   m_filePassword(dirBase.getFile("password")),
684)   m_fileTarget(dirBase.getFile("target")),
685)   m_configData(),
686)   m_worker(),
687)   m_sharedData(),
688)   m_curConn(nullptr)
689) {
Stefan Schuermans implement common sound dir,...

Stefan Schuermans authored 5 years ago

690)   m_configData.soundDirs.clear();
691)   m_configData.soundDirs.push_back(dirBase.getSubdir("sounds"));
692)   m_configData.soundDirs.push_back(dirBase.getParent().getParent()
693)                                           .getSubdir("sounds"));
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

694)   m_configData.logFileName = dirBase.getFile("sip.log").getPath();
695)   m_sharedData.run = true;
696)   m_sharedData.reregister = false;
697)   m_sharedData.reqPlay = false;
698)   m_sharedData.hangup = false;
699)   m_sharedData.accepted = false;
700)   m_sharedData.terminated = false;
701) 
702)   m_mgrs.m_callMgr.requestTimeCall(this, Time::now());
703) 
704) #ifdef BLINKER_CFG_LINPHONE
705)   m_worker = std::thread(linphone::worker, std::ref(m_configData),
706)                          std::ref(m_sharedData));
707) #endif
708) 
709)   sipRegister();
710) }
711) 
712) /// virtual destructor
713) SipPhone::~SipPhone()
714) {
715)   if (m_curConn) {
716)     m_curConn->close();
717)     m_curConn = nullptr;
718)   }
719) 
720)   sipDeregister();
721) 
722)   {
723)     std::lock_guard<std::mutex> lock(m_sharedData.mtx);
724)     m_sharedData.run = false;
725)   }
726)   m_sharedData.cond.notify_one();
727) #ifdef BLINKER_CFG_LINPHONE
728)   m_worker.join();
729) #endif
730) 
731)   m_mgrs.m_callMgr.cancelTimeCall(this);
732) }
733) 
734) /// check for update of configuration
735) void SipPhone::updateConfig()
736) {
737)   // server, username or password file modified -> re-connect
738)   if (m_fileServer.checkModified() || m_fileUsername.checkModified() ||
739)                                       m_filePassword.checkModified()) {
740)     // re-register
741)     sipDeregister();
742)     sipRegister();
743)   }
744) 
745)   // target file was modified -> re-get target operator interface to connect to
746)   if (m_fileTarget.checkModified()) {
747)     m_fileTarget.update();
748)   }
749) }
750) 
751) /// callback when requested time reached
752) void SipPhone::timeCall()
753) {
754)   Time now = Time::now();
755) 
756)   // get information from SIP phone worker
757)   bool accepted;
758)   std::string dtmf;
759)   bool terminated;
760)   {
761)     std::lock_guard<std::mutex> lock(m_sharedData.mtx);
762)     accepted = m_sharedData.accepted;
763)     m_sharedData.accepted = false;
764)     dtmf = m_sharedData.dtmf;
765)     m_sharedData.dtmf.clear();
766)     terminated = m_sharedData.terminated;
767)     m_sharedData.terminated = false;
768)   }
769) 
770)   // phone call has terminated or new one has been accepted
771)   if (terminated || accepted) {
772)     // close connection if any
773)     if (m_curConn) {
774)       // request hang up of phone
775)       {
776)         std::lock_guard<std::mutex> lock(m_sharedData.mtx);
777)         m_sharedData.hangup = true;
778)       }
779)       // close and forget connection
780)       m_curConn->close();
781)       m_curConn = nullptr;
782)     }
783)   }
784) 
785)   // phone call has been accepted
786)   if (accepted) {
787)     // try to open new connection to target operator interface
788)     if (m_fileTarget.m_valid) {
789)       m_curConn = m_mgrs.m_opMgr.connect(m_fileTarget.m_obj.m_str, this);
790)     }
Stefan Schuermans sip: hang up after connect...

Stefan Schuermans authored 5 years ago

791)     // operator connection failed -> request hang up of phone
792)     if (! m_curConn) {
793)       std::lock_guard<std::mutex> lock(m_sharedData.mtx);
794)       m_sharedData.hangup = true;
795)     }