#include #include #include #include #include #include #include #include #include #include #include #include #include #include //-lboost_chrono #include //split #include #include #include #include // https://github.com/compuphase/minIni #include "./minIni/minIni.h" #define sizearray(a) (sizeof(a) / sizeof((a)[0])) //g++ linphone.cpp minIni/minIni.c -std=c++17 -lpthread -lboost_system -lboost_thread -lboost_chrono -lrt -pthread -lboost_filesystem -o linphone //https://github.com/mgaman/PDUlib/tree/master std::string linphone_ini="/root/.linphonerc"; char str_ini[100]; std::string ExecCmd(std::string command){ char buffer[128]; std::string cmd_out = ""; // open pipe to file and execute command in linux terminal FILE* pipe = popen(command.c_str(), "r"); if (!pipe) return "popen failed!"; // read till end of process: while (!feof(pipe)) { // read output of the sent command and add to result if (fgets(buffer, 128, pipe) != NULL) cmd_out += buffer; } pclose(pipe); // returns the output of terminal in string format return cmd_out; } bool isNumber(std::string str) { double d; std::istringstream is(str); is >> d; return !is.fail() && is.eof(); } bool file_exists(std::string file){ boost::filesystem::path p(file); // avoid repeated path construction below if (exists(p)){ // does path p actually exist? if (is_regular_file(p)){ // is path p a regular file? //std::cout << p << " size is " << file_size(p) << '\n'; return true; } else if (is_directory(p)){ // is path p a directory? //std::cout << p << " is a directory\n"; } else{ //std::cout << p << " exists, but is not a regular file or directory\n"; } } else{ //std::cout << p << " does not exist\n"; } return false; } bool init_linphone(){ std::string sip_domain="doorbell.doordk.com"; std::string sip_user="6000"; std::string sip_password="1234"; std::string linphone_port="5062"; std::string video_capture="1"; std::string video_display="0"; std::string video_show_local="0"; std::string video_size="vga"; std::string video_device="V4L2: /dev/video5"; std::string audio_playback_dev_id="ALSA Unknown: USB PnP Sound Device"; std::string audio_ringer_dev_id="ALSA Unknown: USB PnP Sound Device"; std::string audio_capture_dev_id="ALSA Unknown: USB PnP Sound Device"; std::string audio_media_dev_id="ALSA Unknown: USB PnP Sound Device"; std::string auto_send_ringing_on="1"; if( file_exists(linphone_ini) ){ int codec_idx=0; //Audio codec std::string codec; std::string codec_str=""; std::vector strs; strs.push_back("PCMU"); strs.push_back("PCMA"); do{ codec="audio_codec_"+std::to_string(codec_idx); ini_gets(codec.c_str(), "mime", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string codec_str_A(str_ini); codec_str=codec_str_A; boost::algorithm::trim(codec_str); if( codec_str != "dummy"){ ini_gets(codec.c_str(), "enabled", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string codec_enabled(str_ini); boost::algorithm::trim(codec_enabled); if( codec_enabled != "dummy"){ bool set=true; for (auto it = strs.begin(); it != strs.end(); ++it){ if( *it == codec_str ){ if( codec_enabled == "0" ){ //std::cout << "Enable codec_str: " << codec_str << std::endl; ini_puts(codec.c_str(), "enabled", "1", linphone_ini.c_str()); } set=false; break; } } if( (codec_enabled == "1") && set ){ //std::cout << "Disable codec_str: " << codec_str << std::endl; ini_puts(codec.c_str(), "enabled", "0", linphone_ini.c_str()); } } } codec_idx++; }while(codec_str != "dummy"); strs.clear(); //Video codec strs.push_back("VP8"); strs.push_back("H264"); codec_idx=0; do{ codec="video_codec_"+std::to_string(codec_idx); ini_gets(codec.c_str(), "mime", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string codec_str_A(str_ini); codec_str=codec_str_A; boost::algorithm::trim(codec_str); if( codec_str != "dummy"){ ini_gets(codec.c_str(), "enabled", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string codec_enabled(str_ini); boost::algorithm::trim(codec_enabled); if( codec_enabled != "dummy"){ bool set=true; for (auto it = strs.begin(); it != strs.end(); ++it){ if( *it == codec_str ){ if( codec_enabled == "0" ){ //std::cout << "Enable codec_str: " << codec_str << std::endl; ini_puts(codec.c_str(), "enabled", "1", linphone_ini.c_str()); } set=false; break; } } if( (codec_enabled == "1") && set ){ //std::cout << "Disable codec_str: " << codec_str << std::endl; ini_puts(codec.c_str(), "enabled", "0", linphone_ini.c_str()); } } } codec_idx++; }while(codec_str != "dummy"); ini_gets("proxy_0", "reg_proxy", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string reg_proxy(str_ini); boost::algorithm::trim(reg_proxy); std::string reg_proxy_str="sip:"+sip_domain; if( reg_proxy == reg_proxy_str ){ //std::cout << "reg_proxy: " << reg_proxy << std::endl; }else{ ini_puts("proxy_0", "reg_proxy", reg_proxy_str.c_str(), linphone_ini.c_str()); } ini_gets("proxy_0", "reg_identity", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string reg_identity(str_ini); boost::algorithm::trim(reg_identity); std::string reg_identity_str="sip:"+sip_user+"@"+sip_domain; if( reg_identity == reg_identity_str ){ //std::cout << "reg_identity: " << reg_identity << std::endl; }else{ ini_puts("proxy_0", "reg_identity", reg_identity_str.c_str(), linphone_ini.c_str()); } ini_gets("sip", "sip_port", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string sip_port(str_ini); boost::algorithm::trim(sip_port); if( sip_port == linphone_port ){ //std::cout << "linphone_port: " << sip_port << std::endl; }else{ ini_puts("sip", "sip_port", linphone_port.c_str(), linphone_ini.c_str()); } ini_gets("sip", "auto_send_ringing", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string auto_send_ringing(str_ini); boost::algorithm::trim(auto_send_ringing); if( auto_send_ringing == auto_send_ringing_on ){ //std::cout << "auto_send_ringing_on: " << auto_send_ringing << std::endl; }else{ ini_puts("sip", "auto_send_ringing", auto_send_ringing_on.c_str(), linphone_ini.c_str()); } ini_gets("auth_info_0", "username", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string username(str_ini); boost::algorithm::trim(username); if( username == sip_user ){ //std::cout << "sip_user: " << username << std::endl; }else{ ini_puts("auth_info_0", "username", sip_user.c_str(), linphone_ini.c_str()); } ini_gets("video", "capture", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string capture(str_ini); boost::algorithm::trim(capture); if( capture == video_capture ){ //std::cout << "video_capture: " << capture << std::endl; }else{ ini_puts("video", "capture", video_capture.c_str(), linphone_ini.c_str()); } ini_gets("video", "display", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string display(str_ini); boost::algorithm::trim(display); if( display == video_display ){ //std::cout << "video_display: " << display << std::endl; }else{ ini_puts("video", "display", video_display.c_str(), linphone_ini.c_str()); } ini_gets("video", "show_local", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string show_local(str_ini); boost::algorithm::trim(show_local); if( show_local == video_show_local ){ //std::cout << "video_show_local: " << show_local << std::endl; }else{ ini_puts("video", "show_local", video_show_local.c_str(), linphone_ini.c_str()); } ini_gets("video", "size", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string size(str_ini); boost::algorithm::trim(size); if( size == video_size ){ //std::cout << "video_size: " << size << std::endl; }else{ ini_puts("video", "size", video_size.c_str(), linphone_ini.c_str()); } ini_gets("video", "device", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string device(str_ini); boost::algorithm::trim(device); if( device == video_device ){ //std::cout << "video_device: " << device << std::endl; }else{ ini_puts("video", "device", video_device.c_str(), linphone_ini.c_str()); } ini_gets("sound", "playback_dev_id", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string playback_dev_id(str_ini); boost::algorithm::trim(playback_dev_id); if( playback_dev_id == audio_playback_dev_id ){ //std::cout << "audio_playback_dev_id: " << playback_dev_id << std::endl; }else{ ini_puts("sound", "playback_dev_id", audio_playback_dev_id.c_str(), linphone_ini.c_str()); } ini_gets("sound", "ringer_dev_id", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string ringer_dev_id(str_ini); boost::algorithm::trim(ringer_dev_id); if( ringer_dev_id == audio_ringer_dev_id ){ //std::cout << "audio_ringer_dev_id: " << ringer_dev_id << std::endl; }else{ ini_puts("sound", "ringer_dev_id", audio_ringer_dev_id.c_str(), linphone_ini.c_str()); } ini_gets("sound", "capture_dev_id", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string capture_dev_id(str_ini); boost::algorithm::trim(capture_dev_id); if( capture_dev_id == audio_capture_dev_id ){ //std::cout << "audio_capture_dev_id: " << capture_dev_id << std::endl; }else{ ini_puts("sound", "capture_dev_id", audio_capture_dev_id.c_str(), linphone_ini.c_str()); } ini_gets("sound", "media_dev_id", "dummy", str_ini, sizearray(str_ini), linphone_ini.c_str()); std::string media_dev_id(str_ini); boost::algorithm::trim(media_dev_id); if( media_dev_id == audio_media_dev_id ){ //std::cout << "audio_media_dev_id: " << media_dev_id << std::endl; }else{ ini_puts("sound", "media_dev_id", audio_media_dev_id.c_str(), linphone_ini.c_str()); } return true; } return false; } bool is_linphone_registred(){ std::string ret=ExecCmd("linphonecsh generic \"status register\""); std::cout << "linphonec status register: " << ret << std::endl; boost::algorithm::trim(ret); size_t sip_register = ret.find("identity=sip:"); if( sip_register != std::string::npos ){ //std::cout << "Linphone register OK." << std::endl; return true; }else{ //std::cout << "Error:Linphone register NOB." << std::endl; return false; } } int main(int argc, char **argv){ char letter; std::string cmd_str=""; std::string linphone_log_file = "/home/rock/linphone_log.txt"; std::string ret=ExecCmd("ps aux | pgrep linphonec"); boost::algorithm::trim(ret); if( ret != "" ){ std::cout << "pid linphonec: " << ret << std::endl; boost::process::child::child_handle pid{std::atoi(ret.c_str())}; std::error_code ec; boost::process::detail::api::terminate(pid, ec); std::cout << "Allways do killed linphonec at start up to start a new one: " << ec.message() << std::endl; } if( ! init_linphone() ){ std::cout << "Error init_linphone(). Abort." << std::endl; return 1; } cmd_str="linphonecsh init -a -C -c /root/.linphonerc -d 6 -l "+linphone_log_file; ExecCmd(cmd_str); boost::this_thread::sleep_for(boost::chrono::seconds(1)); while(1) { scanf(" %c", &letter ); if( letter == 'x' ){ break; }else if( letter == 'a' ){ ret=ExecCmd("linphonecsh generic \"ports\""); std::cout << "linphonec port: " << ret << std::endl; std::vector strs; boost::split(strs, ret , boost::is_any_of("\n")); if( strs.size() > 0 ){ std::string port_str=strs[0]; boost::algorithm::trim(port_str); std::size_t found = port_str.find_last_of(" "); if( found != std::string::npos ){ std::string lin_port=port_str.substr(found+1); boost::algorithm::trim(lin_port); if( isNumber(lin_port) ){ /*if( lin_port != linphone_port ){ ret=ExecCmd("linphonecsh generic \"ports sip "+linphone_port+"\""); std::cout << "New linphonec port: " << ret << std::endl; }*/ } } if( strs.size() > 1 ){ std::string audio_rtp_str=strs[1]; boost::algorithm::trim(audio_rtp_str); std::cout << "linphonec audio_rtp_str: " << audio_rtp_str << std::endl; } if( strs.size() > 2 ){ std::string video_rtp_str=strs[2]; boost::algorithm::trim(video_rtp_str); std::cout << "linphonec video_rtp_str: " << video_rtp_str << std::endl; } if( is_linphone_registred() ){ std::cout << "Linphone register OK." << std::endl; }else{ std::cout << "Error:Linphone register NOB." << std::endl; } } }else if( letter == 'b' ){ ret=ExecCmd("linphonecsh generic \"ports\""); std::cout << "ports:\n" << ret << std::endl; ret=ExecCmd("linphonecsh generic \"soundcard list\""); std::cout << "soundcard list:\n" << ret << std::endl; ret=ExecCmd("linphonecsh generic \"stun\""); std::cout << "stun:\n" << ret << std::endl; ret=ExecCmd("linphonecsh generic \"firewall\""); std::cout << "firewall:\n" << ret << std::endl; ret=ExecCmd("linphonecsh generic \"webcam list\""); std::cout << "webcam list:\n" << ret << std::endl; ret=ExecCmd("linphonecsh generic \"codec list\""); std::cout << "codec list:\n" << ret << std::endl; ret=ExecCmd("linphonecsh generic \"vcodec list\""); std::cout << "vcodec list:\n" << ret << std::endl; ret=ExecCmd("linphonecsh generic \"autoanswer\""); std::cout << "autoanswer:\n" << ret << std::endl; }else if( letter == 'c' ){ } } if( is_linphone_registred() ){ ExecCmd("linphonecsh generic \"unregister\""); boost::this_thread::sleep_for(boost::chrono::seconds(1)); } ret=ExecCmd("ps aux | pgrep linphonec"); boost::algorithm::trim(ret); if( ret != "" ){ boost::process::child::child_handle pid{std::atoi(ret.c_str())}; std::error_code ec; boost::process::detail::api::terminate(pid, ec); std::cout << " killed: " << ec.message() << std::endl; } return 0; }