dabb8bffb29db725c3544aabafb3b1d8bf8f3457
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) 
421)   // set auth data
422)   if (! username.empty() && ! password.empty()) {
423)     LinphoneAuthInfo *auth_info =
424)         linphone_auth_info_new(username.c_str(), username.c_str(),
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

430)       linphone_core_cbs_unref(data.callbacks);
431)       data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

432)       return;
433)     }
434)     linphone_core_add_auth_info(data.lc, auth_info);
435)     log(data, "auth info set");
436)   } else {
437)     log(data, "no auth data available");
438)   }
439) 
440)   // configure proxy
441)   std::string sipserver = "sip:" + server;
442)   std::string identity = "sip:" + username + "@" + server;
443)   LinphoneProxyConfig *proxy = linphone_core_create_proxy_config(data.lc);
444)   if (! proxy) {
445)     log(data, "failed to create proxy config");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

448)     linphone_core_cbs_unref(data.callbacks);
449)     data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

450)     return;
451)   }
452)   linphone_proxy_config_set_server_addr(proxy, sipserver.c_str());
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

453)   LinphoneAddress *addr =
454)       linphone_proxy_config_normalize_sip_uri(proxy, identity.c_str());
455)   if (addr != NULL) {
456)     linphone_proxy_config_set_identity_address(proxy, addr);
457)   }
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

458)   linphone_proxy_config_enable_register(proxy, TRUE);
459)   linphone_core_add_proxy_config(data.lc, proxy);
460)   log(data, "proxy config set");
461) 
462)   // tell linphone not to rind and to use files instead of sound card
463)   linphone_core_set_ring(data.lc, nullptr);
464)   linphone_core_use_files(data.lc, TRUE);
465)   linphone_core_set_play_file(data.lc, nullptr);
466) }
467) 
468) /**
469)  * @brief deregister if active
470)  * @param[in,out] data data of SIP client
471)  */
472) void do_deregister(Data &data)
473) {
474)   if (! data.lc) {
475)     return;
476)   }
477) 
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

478)   log(data, "unreferencing...");
479)   linphone_core_unref(data.lc);
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

481)   linphone_core_cbs_unref(data.callbacks);
482)   data.callbacks = nullptr;
Stefan Schuermans implement SIP

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

485) }
486) 
487) /**
488)  * @brief play sound on call if active
489)  * @param[in,out] data data of SIP client
490)  * @param[in] name name of sound
491)  */
492) void do_play(Data &data, std::string const &name)
493) {
494)   if (! data.lc) {
495)     return;
496)   }
497)   if (! data.call) {
498)     return;
499)   }
500) 
501)   std::stringstream line;
502)   line << "playing sound \"" << name << "\"";
503)   log(data, line.str());
504)   set_playback(data, name);
505)   start_playback(data);
506) }
507) 
508) /**
509)  * @brief hangup call if active
510)  * @param[in,out] data data of SIP client
511)  */
512) void do_hangup(Data &data)
513) {
514)   if (! data.lc) {
515)     return;
516)   }
517)   if (! data.call) {
518)     return;
519)   }
520) 
521)   log(data, "terminating call...");
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

523)   data.call = nullptr;
524)   log(data, "call terminated");
525) }
526) 
527) /**
528)  * @brief linphone worker thread
529)  * @param[in] soundDir directory of sound files
530)  * @param[in,out] data shared data for communication with main Blinker thread
531)  */
532) void worker(SipPhone::ConfigData const &configData,
533)             SipPhone::SharedData &sharedData)
534) {
535)   // set up data of SIP client
536)   Data data;
537)   data.configData = &configData;
538)   data.sharedData = &sharedData;
Stefan Schuermans update to liblinphone 3.12

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

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

Stefan Schuermans authored 5 years ago

735)     // operator connection failed -> request hang up of phone
736)     if (! m_curConn) {
737)       std::lock_guard<std::mutex> lock(m_sharedData.mtx);
738)       m_sharedData.hangup = true;
739)     }