diff --git a/.gitmodules b/.gitmodules index ac5736dee34c1d5ce00da348b2a800929afc4e42..0b47f041732c6abf8b2c30036cfe7eaa1bf38f33 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "kde"] path = kde - url = https://github.com/Elv13/sflphone-kde.git + url = http://anongit.kde.org/sflphone-kde.git diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp index 6ff8cc0c64908a2705c5f7ea046d7c3f7ea3343d..3db92c30ad9b4441b80eaaa9b487abec6cf69e19 100644 --- a/daemon/src/account.cpp +++ b/daemon/src/account.cpp @@ -46,6 +46,7 @@ const char * const Account::AUDIO_CODECS_KEY = "audioCodecs"; // 0/9/110/1 const char * const Account::VIDEO_CODECS_KEY = "videoCodecs"; const char * const Account::VIDEO_CODEC_ENABLED = "enabled"; const char * const Account::VIDEO_CODEC_NAME = "name"; +const char * const Account::VIDEO_CODEC_PARAMETERS ="parameters"; const char * const Account::VIDEO_CODEC_BITRATE = "bitrate"; const char * const Account::RINGTONE_PATH_KEY = "ringtonePath"; const char * const Account::RINGTONE_ENABLED_KEY = "ringtoneEnabled"; @@ -146,7 +147,7 @@ namespace { bool isCodecValid(const map<string, string> &codec, const vector<map<string, string> > &defaults) { - map<string, string>::const_iterator name(codec.find(Account::VIDEO_CODEC_NAME)); + const map<string, string>::const_iterator name(codec.find(Account::VIDEO_CODEC_NAME)); if (name == codec.end()) { ERROR("Field \"name\" missing in codec specification"); return false; @@ -154,7 +155,7 @@ namespace { // check that it's in the list of valid codecs and that it has all the required fields for (vector<map<string, string> >::const_iterator i = defaults.begin(); i != defaults.end(); ++i) { - map<string, string>::const_iterator defaultName = i->find(Account::VIDEO_CODEC_NAME); + const map<string, string>::const_iterator defaultName = i->find(Account::VIDEO_CODEC_NAME); if (defaultName->second == name->second) { return isFieldValid(codec, Account::VIDEO_CODEC_BITRATE, isPositiveInteger) and isFieldValid(codec, Account::VIDEO_CODEC_ENABLED, isBoolean); @@ -199,7 +200,7 @@ void Account::setActiveAudioCodecs(const vector<string> &list) audioCodecList_.clear(); // list contains the ordered payload of active codecs picked by the user for this account - // we used the CodecOrder vector to save the order. + // we used the codec vector to save the order. for (vector<string>::const_iterator iter = list.begin(); iter != list.end(); ++iter) { int payload = std::atoi(iter->c_str()); diff --git a/daemon/src/account.h b/daemon/src/account.h index ee42256d8d5b110ce96c659132b122a063a6609d..788340bb0e1af6aae95b29482c74b6b14f051185 100644 --- a/daemon/src/account.h +++ b/daemon/src/account.h @@ -141,7 +141,7 @@ class Account : public Serializable { getActiveVideoCodecs() const; /* Accessor to data structures - * @return CodecOrder& The list that reflects the user's choice + * @return The list that reflects the user's choice */ std::vector<int> getActiveAudioCodecs() const { return audioCodecList_; @@ -185,6 +185,7 @@ class Account : public Serializable { static const char * const VIDEO_CODEC_ENABLED; static const char * const VIDEO_CODEC_NAME; + static const char * const VIDEO_CODEC_PARAMETERS; static const char * const VIDEO_CODEC_BITRATE; private: NON_COPYABLE(Account); diff --git a/daemon/src/account_schema.h b/daemon/src/account_schema.h index 1e769cdb75a77894656c879f7c0ec91177ca2a02..46d1b436fc221186e83025c5f1d845507a616c0a 100644 --- a/daemon/src/account_schema.h +++ b/daemon/src/account_schema.h @@ -38,68 +38,75 @@ */ // Account identifier -static const char *const CONFIG_ACCOUNT_ID = "Account.id"; +static const char *const CONFIG_ACCOUNT_ID = "Account.id"; // Common account parameters -static const char *const CONFIG_ACCOUNT_TYPE = "Account.type"; -static const char *const CONFIG_ACCOUNT_ALIAS = "Account.alias"; -static const char *const CONFIG_ACCOUNT_MAILBOX = "Account.mailbox"; -static const char *const CONFIG_ACCOUNT_ENABLE = "Account.enable"; -static const char *const CONFIG_ACCOUNT_REGISTRATION_EXPIRE = "Account.registrationExpire"; -static const char *const CONFIG_ACCOUNT_REGISTRATION_STATUS = "Account.registrationStatus"; +static const char *const CONFIG_ACCOUNT_TYPE = "Account.type"; +static const char *const CONFIG_ACCOUNT_ALIAS = "Account.alias"; +static const char *const CONFIG_ACCOUNT_MAILBOX = "Account.mailbox"; +static const char *const CONFIG_ACCOUNT_ENABLE = "Account.enable"; +static const char *const CONFIG_ACCOUNT_REGISTRATION_EXPIRE = "Account.registrationExpire"; +static const char *const CONFIG_ACCOUNT_REGISTRATION_STATUS = "Account.registrationStatus"; static const char *const CONFIG_ACCOUNT_REGISTRATION_STATE_CODE = "Account.registrationCode"; static const char *const CONFIG_ACCOUNT_REGISTRATION_STATE_DESC = "Account.registrationDescription"; -static const char *const CONFIG_CREDENTIAL_NUMBER = "Credential.count"; -static const char *const CONFIG_ACCOUNT_DTMF_TYPE = "Account.dtmfType"; -static const char *const CONFIG_RINGTONE_PATH = "Account.ringtonePath"; -static const char *const CONFIG_RINGTONE_ENABLED = "Account.ringtoneEnabled"; -static const char *const CONFIG_KEEP_ALIVE_ENABLED = "Account.keepAliveEnabled"; +static const char *const CONFIG_CREDENTIAL_NUMBER = "Credential.count"; +static const char *const CONFIG_ACCOUNT_DTMF_TYPE = "Account.dtmfType"; +static const char *const CONFIG_RINGTONE_PATH = "Account.ringtonePath"; +static const char *const CONFIG_RINGTONE_ENABLED = "Account.ringtoneEnabled"; +static const char *const CONFIG_KEEP_ALIVE_ENABLED = "Account.keepAliveEnabled"; -static const char *const CONFIG_ACCOUNT_HOSTNAME = "Account.hostname"; -static const char *const CONFIG_ACCOUNT_USERNAME = "Account.username"; -static const char *const CONFIG_ACCOUNT_ROUTESET = "Account.routeset"; -static const char *const CONFIG_ACCOUNT_PASSWORD = "Account.password"; -static const char *const CONFIG_ACCOUNT_REALM = "Account.realm"; -static const char *const CONFIG_ACCOUNT_DEFAULT_REALM = "*"; -static const char *const CONFIG_ACCOUNT_USERAGENT = "Account.useragent"; -static const char *const CONFIG_LOCAL_INTERFACE = "Account.localInterface"; -static const char *const CONFIG_PUBLISHED_SAMEAS_LOCAL = "Account.publishedSameAsLocal"; -static const char *const CONFIG_LOCAL_PORT = "Account.localPort"; -static const char *const CONFIG_PUBLISHED_PORT = "Account.publishedPort"; -static const char *const CONFIG_PUBLISHED_ADDRESS = "Account.publishedAddress"; +static const char *const CONFIG_DEFAULT_REGISTRATION_EXPIRE = "60"; -static const char *const CONFIG_DISPLAY_NAME = "Account.displayName"; -static const char *const CONFIG_DEFAULT_ADDRESS = "0.0.0.0"; +static const char *const CONFIG_ACCOUNT_HOSTNAME = "Account.hostname"; +static const char *const CONFIG_ACCOUNT_USERNAME = "Account.username"; +static const char *const CONFIG_ACCOUNT_ROUTESET = "Account.routeset"; +static const char *const CONFIG_ACCOUNT_PASSWORD = "Account.password"; +static const char *const CONFIG_ACCOUNT_REALM = "Account.realm"; +static const char *const CONFIG_ACCOUNT_DEFAULT_REALM = "*"; +static const char *const CONFIG_ACCOUNT_USERAGENT = "Account.useragent"; + +static const char *const CONFIG_LOCAL_INTERFACE = "Account.localInterface"; +static const char *const CONFIG_INTERFACE = "Account.interface"; +static const char *const CONFIG_PUBLISHED_SAMEAS_LOCAL = "Account.publishedSameAsLocal"; +static const char *const CONFIG_LOCAL_PORT = "Account.localPort"; +static const char *const CONFIG_PUBLISHED_PORT = "Account.publishedPort"; +static const char *const CONFIG_PUBLISHED_ADDRESS = "Account.publishedAddress"; +static const char *const CONFIG_DEFAULT_LOCAL_PORT = "5060"; +static const char *const CONFIG_DEFAULT_PUBLISHED_PORT = "5060"; +static const char *const CONFIG_DEFAULT_PUBLISHED_SAMEAS_LOCAL = "true"; +static const char *const CONFIG_DEFAULT_INTERFACE = "default"; + +static const char *const CONFIG_DISPLAY_NAME = "Account.displayName"; +static const char *const CONFIG_DEFAULT_ADDRESS = "0.0.0.0"; // SIP specific parameters -static const char *const CONFIG_SIP_PROXY = "SIP.proxy"; -static const char *const CONFIG_STUN_SERVER = "STUN.server"; -static const char *const CONFIG_STUN_ENABLE = "STUN.enable"; +static const char *const CONFIG_STUN_SERVER = "STUN.server"; +static const char *const CONFIG_STUN_ENABLE = "STUN.enable"; // SRTP specific parameters -static const char *const CONFIG_SRTP_ENABLE = "SRTP.enable"; -static const char *const CONFIG_SRTP_KEY_EXCHANGE = "SRTP.keyExchange"; -static const char *const CONFIG_SRTP_ENCRYPTION_ALGO = "SRTP.encryptionAlgorithm"; // Provided by ccRTP,0=NULL,1=AESCM,2=AESF8 -static const char *const CONFIG_SRTP_RTP_FALLBACK = "SRTP.rtpFallback"; -static const char *const CONFIG_ZRTP_HELLO_HASH = "ZRTP.helloHashEnable"; -static const char *const CONFIG_ZRTP_DISPLAY_SAS = "ZRTP.displaySAS"; -static const char *const CONFIG_ZRTP_NOT_SUPP_WARNING = "ZRTP.notSuppWarning"; -static const char *const CONFIG_ZRTP_DISPLAY_SAS_ONCE = "ZRTP.displaySasOnce"; +static const char *const CONFIG_SRTP_ENABLE = "SRTP.enable"; +static const char *const CONFIG_SRTP_KEY_EXCHANGE = "SRTP.keyExchange"; +static const char *const CONFIG_SRTP_ENCRYPTION_ALGO = "SRTP.encryptionAlgorithm"; // Provided by ccRTP,0=NULL,1=AESCM,2=AESF8 +static const char *const CONFIG_SRTP_RTP_FALLBACK = "SRTP.rtpFallback"; +static const char *const CONFIG_ZRTP_HELLO_HASH = "ZRTP.helloHashEnable"; +static const char *const CONFIG_ZRTP_DISPLAY_SAS = "ZRTP.displaySAS"; +static const char *const CONFIG_ZRTP_NOT_SUPP_WARNING = "ZRTP.notSuppWarning"; +static const char *const CONFIG_ZRTP_DISPLAY_SAS_ONCE = "ZRTP.displaySasOnce"; -static const char *const CONFIG_TLS_LISTENER_PORT = "TLS.listenerPort"; -static const char *const CONFIG_TLS_ENABLE = "TLS.enable"; -static const char *const CONFIG_TLS_CA_LIST_FILE = "TLS.certificateListFile"; -static const char *const CONFIG_TLS_CERTIFICATE_FILE = "TLS.certificateFile"; -static const char *const CONFIG_TLS_PRIVATE_KEY_FILE = "TLS.privateKeyFile"; -static const char *const CONFIG_TLS_PASSWORD = "TLS.password"; -static const char *const CONFIG_TLS_METHOD = "TLS.method"; -static const char *const CONFIG_TLS_CIPHERS = "TLS.ciphers"; -static const char *const CONFIG_TLS_SERVER_NAME = "TLS.serverName"; -static const char *const CONFIG_TLS_VERIFY_SERVER = "TLS.verifyServer"; -static const char *const CONFIG_TLS_VERIFY_CLIENT = "TLS.verifyClient"; -static const char *const CONFIG_TLS_REQUIRE_CLIENT_CERTIFICATE = "TLS.requireClientCertificate"; -static const char *const CONFIG_TLS_NEGOTIATION_TIMEOUT_SEC = "TLS.negotiationTimeoutSec"; -static const char *const CONFIG_TLS_NEGOTIATION_TIMEOUT_MSEC = "TLS.negotiationTimemoutMsec"; +static const char *const CONFIG_TLS_LISTENER_PORT = "TLS.listenerPort"; +static const char *const CONFIG_TLS_ENABLE = "TLS.enable"; +static const char *const CONFIG_TLS_CA_LIST_FILE = "TLS.certificateListFile"; +static const char *const CONFIG_TLS_CERTIFICATE_FILE = "TLS.certificateFile"; +static const char *const CONFIG_TLS_PRIVATE_KEY_FILE = "TLS.privateKeyFile"; +static const char *const CONFIG_TLS_PASSWORD = "TLS.password"; +static const char *const CONFIG_TLS_METHOD = "TLS.method"; +static const char *const CONFIG_TLS_CIPHERS = "TLS.ciphers"; +static const char *const CONFIG_TLS_SERVER_NAME = "TLS.serverName"; +static const char *const CONFIG_TLS_VERIFY_SERVER = "TLS.verifyServer"; +static const char *const CONFIG_TLS_VERIFY_CLIENT = "TLS.verifyClient"; +static const char *const CONFIG_TLS_REQUIRE_CLIENT_CERTIFICATE = "TLS.requireClientCertificate"; +static const char *const CONFIG_TLS_NEGOTIATION_TIMEOUT_SEC = "TLS.negotiationTimeoutSec"; +static const char *const CONFIG_TLS_NEGOTIATION_TIMEOUT_MSEC = "TLS.negotiationTimemoutMsec"; #endif diff --git a/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp b/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp index b97ea7ca9ddae2675bc1689a7c8b3e999f3d55a3..eb70e5401110dca915348b48b319792dc28d133e 100644 --- a/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp +++ b/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp @@ -40,8 +40,6 @@ namespace sfl { -static const SFLDataFormat INIT_FADE_IN_FACTOR = 32000; - #ifdef RECTODISK std::ofstream rtpResampled ("testRtpOutputResampled.raw", std::ifstream::binary); std::ofstream rtpNotResampled("testRtpOutput.raw", std::ifstream::binary); @@ -69,7 +67,7 @@ AudioRtpRecord::AudioRtpRecord() : , codecFrameSize_(0) , converterSamplingRate_(0) , dtmfQueue_() - , fadeFactor_(INIT_FADE_IN_FACTOR) + , fadeFactor_(1.0 / 32000.0) #if HAVE_SPEEXDSP , noiseSuppressEncode_(0) , noiseSuppressDecode_(0) @@ -259,15 +257,15 @@ void AudioRtpRecordHandler::processDataDecode(unsigned char *spkrData, size_t si void AudioRtpRecord::fadeInDecodedData(size_t size) { - // if factor reaches 0, this function should have no effect - if (fadeFactor_ <= 0 or size > decData_.size()) + // if factor reaches 1, this function should have no effect + if (fadeFactor_ >= 1.0 or size > decData_.size()) return; std::transform(decData_.begin(), decData_.begin() + size, decData_.begin(), - std::bind1st(std::divides<double>(), fadeFactor_)); + std::bind1st(std::multiplies<double>(), fadeFactor_)); // Factor used to increase volume in fade in - const SFLDataFormat FADEIN_STEP_SIZE = 4; - fadeFactor_ /= FADEIN_STEP_SIZE; + const double FADEIN_STEP_SIZE = 4.0; + fadeFactor_ *= FADEIN_STEP_SIZE; } } diff --git a/daemon/src/audio/audiortp/audio_rtp_record_handler.h b/daemon/src/audio/audiortp/audio_rtp_record_handler.h index 4ee32ef605a421c336c7563c509a2112be4f7b7e..0f0ebb0d64201f21f6fe33e49e1fdaca951e963e 100644 --- a/daemon/src/audio/audiortp/audio_rtp_record_handler.h +++ b/daemon/src/audio/audiortp/audio_rtp_record_handler.h @@ -89,7 +89,7 @@ class AudioRtpRecord { int codecFrameSize_; int converterSamplingRate_; std::list<DTMFEvent> dtmfQueue_; - SFLDataFormat fadeFactor_; + double fadeFactor_; #if HAVE_SPEEXDSP NoiseSuppress *noiseSuppressEncode_; diff --git a/daemon/src/audio/codecs/audiocodecfactory.cpp b/daemon/src/audio/codecs/audiocodecfactory.cpp index 64e54381104f6a855c51e6cc558e7e39c28fea6e..769dd32aa63bd1432a291872ecae90b3c287f005 100644 --- a/daemon/src/audio/codecs/audiocodecfactory.cpp +++ b/daemon/src/audio/codecs/audiocodecfactory.cpp @@ -128,7 +128,7 @@ void AudioCodecFactory::saveActiveCodecs(const std::vector<std::string>& list) { defaultCodecList_.clear(); // list contains the ordered payload of active codecs picked by the user - // we used the CodecOrder vector to save the order. + // we used the codec vector to save the order. for (std::vector<std::string>::const_iterator iter = list.begin(); iter != list.end(); ++iter) { int payload = std::atoi(iter->c_str()); diff --git a/daemon/src/dbus/configurationmanager-introspec.xml b/daemon/src/dbus/configurationmanager-introspec.xml index 782e035a311901f8e369042eb3e4490069cadcc6..a6324749868c8fe4c05b949f79db61fbd516805b 100644 --- a/daemon/src/dbus/configurationmanager-introspec.xml +++ b/daemon/src/dbus/configurationmanager-introspec.xml @@ -6,6 +6,12 @@ Used to handle the configuration stuff: accounts settings, account registration, user preferences, ... </tp:docstring> + <method name="getAccountTemplate" tp:name-for-bindings="getAccountTemplate"> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MapStringString"/> + <arg type="a{ss}" name="details" direction="out" tp:type="String_String_Map"> + </arg> + </method> + <method name="getAccountDetails" tp:name-for-bindings="getAccountDetails"> <tp:docstring> Get all parameters of the specified account. @@ -187,19 +193,15 @@ <method name="registerAllAccounts" tp:name-for-bindings="registerAllAccounts"> <tp:docstring> - Send account registration (REGISTER) for all currently registered account. + Send account registration (REGISTER) for all accounts, even if they are not enabled. </tp:docstring> - Register each account for which enable=true </method> <method name="sendRegister" tp:name-for-bindings="sendRegister"> <tp:docstring> Send account registration (REGISTER) to the registrar. + Register the account if enable=true, unregister if enable=false. </tp:docstring> - Register the account if enable=true, unregister if enable=false. - - @param[in] input accountID - --> <arg type="s" name="accountID" direction="in"> <tp:docstring> The account ID diff --git a/daemon/src/dbus/configurationmanager.cpp b/daemon/src/dbus/configurationmanager.cpp index 76362a79ef8ed8dea807eac735e6b73f0094b8bf..4f607d7ca71a6680a69447e1d4c2d68a5a547abe 100644 --- a/daemon/src/dbus/configurationmanager.cpp +++ b/daemon/src/dbus/configurationmanager.cpp @@ -150,6 +150,18 @@ void ConfigurationManager::registerAllAccounts() Manager::instance().registerAllAccounts(); } +///This function is used as a base for new accounts for clients that support it +std::map<std::string, std::string> ConfigurationManager::getAccountTemplate() +{ + std::map<std::string, std::string> accTemplate; + accTemplate[ CONFIG_LOCAL_PORT ] = CONFIG_DEFAULT_LOCAL_PORT; + accTemplate[ CONFIG_PUBLISHED_PORT ] = CONFIG_DEFAULT_PUBLISHED_PORT; + accTemplate[ CONFIG_PUBLISHED_SAMEAS_LOCAL ] = CONFIG_DEFAULT_PUBLISHED_SAMEAS_LOCAL; + accTemplate[ CONFIG_INTERFACE ] = CONFIG_DEFAULT_INTERFACE; + accTemplate[ CONFIG_ACCOUNT_REGISTRATION_EXPIRE ] = CONFIG_DEFAULT_REGISTRATION_EXPIRE; + return accTemplate; +} + std::string ConfigurationManager::addAccount(const std::map<std::string, std::string>& details) { return Manager::instance().addAccount(details); diff --git a/daemon/src/dbus/configurationmanager.h b/daemon/src/dbus/configurationmanager.h index abc4ea74227d571cd78850b6a5771072aaa8c150..f5df87b8f16950895870be34425ff08d75cb1d17 100644 --- a/daemon/src/dbus/configurationmanager.h +++ b/daemon/src/dbus/configurationmanager.h @@ -61,6 +61,7 @@ class ConfigurationManager ConfigurationManager(DBus::Connection& connection); std::map< std::string, std::string > getAccountDetails(const std::string& accountID); void setAccountDetails(const std::string& accountID, const std::map< std::string, std::string >& details); + std::map<std::string, std::string> getAccountTemplate(); std::string addAccount(const std::map< std::string, std::string >& details); void removeAccount(const std::string& accoundID); void deleteAllCredential(const std::string& accountID); diff --git a/daemon/src/global.h b/daemon/src/global.h index 0377ba68122a2cc08984248bfc97df465ffd698a..522650eaf7453ec0b01f9f6e9f6ba2501e38bbd9 100644 --- a/daemon/src/global.h +++ b/daemon/src/global.h @@ -107,7 +107,4 @@ enum { PAYLOAD_CODEC_SPEEX_32000 = 112 }; -/** The struct to reflect the order the user wants to use the codecs */ -typedef std::vector<int> CodecOrder; - #endif // __GLOBAL_H__ diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 41e42e4d5ebb038805a3638f0ec41bfd3539be54..2a2e1db187f38f3cbcdebe3e1ea08c92762ea345 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -2669,7 +2669,8 @@ ManagerImpl::getAccount(const std::string& accountID) return accountMap_[SIPAccount::IP2IP_PROFILE]; } -std::string ManagerImpl::getAccountIdFromNameAndServer(const std::string& userName, const std::string& server) const +std::string +ManagerImpl::getAccountIdFromNameAndServer(const std::string& userName, const std::string& server) const { DEBUG("username = %s, server = %s", userName.c_str(), server.c_str()); // Try to find the account id from username and server name by full match @@ -2703,6 +2704,16 @@ std::string ManagerImpl::getAccountIdFromNameAndServer(const std::string& userNa } } + // We failed! Then only match the hostname against our proxy + for (AccountMap::const_iterator iter = accountMap_.begin(); iter != accountMap_.end(); ++iter) { + SIPAccount *account = dynamic_cast<SIPAccount *>(iter->second); + + if (account and account->isEnabled() and account->proxyMatch(server)) { + DEBUG("Matching account id in request with proxy %s", server.c_str()); + return iter->first; + } + } + DEBUG("Username %s or server %s doesn't match any account, using IP2IP", userName.c_str(), server.c_str()); return ""; } diff --git a/daemon/src/sip/sdp.cpp b/daemon/src/sip/sdp.cpp index 101498760e58ee879c63e92240b329874b04334b..15799ec896ce22353f7944dac4ecab4045afce63 100644 --- a/daemon/src/sip/sdp.cpp +++ b/daemon/src/sip/sdp.cpp @@ -40,6 +40,10 @@ #include <algorithm> +#ifdef SFL_VIDEO +#include "video/libav_utils.h" +#endif + using std::string; using std::map; using std::vector; @@ -163,7 +167,8 @@ sfl::AudioCodec* Sdp::getSessionAudioMedia() const } -pjmedia_sdp_media *Sdp::setMediaDescriptorLine(bool audio) +pjmedia_sdp_media * +Sdp::setMediaDescriptorLine(bool audio) { pjmedia_sdp_media *med = PJ_POOL_ZALLOC_T(memPool_, pjmedia_sdp_media); @@ -216,13 +221,18 @@ pjmedia_sdp_media *Sdp::setMediaDescriptorLine(bool audio) pjmedia_sdp_rtpmap_to_attr(memPool_, &rtpmap, &attr); med->attr[med->attr_count++] = attr; +#ifdef SFL_VIDEO if (enc_name == "H264") { std::ostringstream os; // FIXME: this should not be hardcoded, it will determine what profile and level // our peer will send us - os << "fmtp:" << dynamic_payload << " profile-level-id=428014"; + std::string profileLevelID(video_codec_list_[i]["parameters"]); + if (profileLevelID.empty()) + profileLevelID = libav_utils::MAX_H264_PROFILE_LEVEL_ID; + os << "fmtp:" << dynamic_payload << " " << profileLevelID; med->attr[med->attr_count++] = pjmedia_sdp_attr_create(memPool_, os.str().c_str(), NULL); } +#endif if (not audio) dynamic_payload++; } @@ -424,12 +434,16 @@ string Sdp::getLineFromSession(const pjmedia_sdp_session *sess, const string &ke return ""; } -string Sdp::getActiveIncomingVideoDescription() const +// FIXME: +// Here we filter out parts of the SDP that libavformat doesn't need to +// know about...we should probably give the video decoder thread the original +// SDP and deal with the streams properly at that level +string Sdp::getIncomingVideoDescription() const { stringstream ss; ss << "v=0" << std::endl; ss << "o=- 0 0 IN IP4 " << localIpAddr_ << std::endl; - ss << "s=sflphone" << std::endl; + ss << "s=" << PACKAGE_NAME << std::endl; ss << "c=IN IP4 " << remoteIpAddr_ << std::endl; ss << "t=0 0" << std::endl; @@ -447,6 +461,11 @@ string Sdp::getActiveIncomingVideoDescription() const std::string vCodecLine(getLineFromSession(activeLocalSession_, s.str())); ss << vCodecLine << std::endl; + std::string profileLevelID; + getProfileLevelID(activeLocalSession_, profileLevelID, payload_num); + if (not profileLevelID.empty()) + ss << "a=fmtp:" << payload_num << " " << profileLevelID << std::endl; + unsigned videoIdx; for (videoIdx = 0; videoIdx < activeLocalSession_->media_count and pj_stricmp2(&activeLocalSession_->media[videoIdx]->desc.media, "video") != 0; ++videoIdx) ; @@ -471,10 +490,12 @@ string Sdp::getActiveIncomingVideoDescription() const return ss.str(); } -std::string Sdp::getActiveOutgoingVideoCodec() const +std::string Sdp::getOutgoingVideoCodec() const { string str("a=rtpmap:"); - str += getActiveOutgoingVideoPayload(); + std::stringstream os; + os << getOutgoingVideoPayload(); + str += os.str(); string vCodecLine(getLineFromSession(activeRemoteSession_, str)); char codec_buf[32]; codec_buf[0] = '\0'; @@ -482,28 +503,55 @@ std::string Sdp::getActiveOutgoingVideoCodec() const return string(codec_buf); } -std::string Sdp::getActiveOutgoingVideoBitrate(const std::string &codec) const -{ - for (vector<map<string, string> >::const_iterator i = video_codec_list_.begin(); i != video_codec_list_.end(); ++i) { - map<string, string>::const_iterator name = i->find("name"); - if (name != i->end() and (codec == name->second)) { - map<string, string>::const_iterator bitrate = i->find("bitrate"); - if (bitrate != i->end()) - return bitrate->second; +namespace { + vector<map<string, string> >::const_iterator + findCodecInList(const vector<map<string, string> > &codecs, const string &codec) + { + for (vector<map<string, string> >::const_iterator i = codecs.begin(); i != codecs.end(); ++i) { + map<string, string>::const_iterator name = i->find("name"); + if (name != i->end() and (codec == name->second)) + return i; + } + return codecs.end(); } +} + +std::string +Sdp::getOutgoingVideoField(const std::string &codec, const char *key) const +{ + const vector<map<string, string> >::const_iterator i = findCodecInList(video_codec_list_, codec); + if (i != video_codec_list_.end()) { + map<string, string>::const_iterator field = i->find(key); + if (field != i->end()) + return field->second; } - return "0"; + return ""; } -std::string Sdp::getActiveOutgoingVideoPayload() const +int +Sdp::getOutgoingVideoPayload() const { string videoLine(getLineFromSession(activeRemoteSession_, "m=video")); int payload_num; if (sscanf(videoLine.c_str(), "m=video %*d %*s %d", &payload_num) != 1) payload_num = 0; + return payload_num; +} + +void +Sdp::getProfileLevelID(const pjmedia_sdp_session *session, + std::string &profile, int payload) const +{ std::ostringstream os; - os << payload_num; - return os.str(); + os << "a=fmtp:" << payload; + string fmtpLine(getLineFromSession(session, os.str())); + const std::string needle("profile-level-id="); + const size_t DIGITS_IN_PROFILE_LEVEL_ID = 6; + const size_t needleLength = needle.size() + DIGITS_IN_PROFILE_LEVEL_ID; + const size_t pos = fmtpLine.find(needle); + if (pos != std::string::npos and fmtpLine.size() >= (pos + needleLength)) + profile = fmtpLine.substr(pos, needleLength); + DEBUG("Using %s", profile.c_str()); } void Sdp::addSdesAttribute(const vector<std::string>& crypto) @@ -539,7 +587,7 @@ namespace { ERROR("Session is NULL when looking for \"%s\" attribute", type); return -1; } - int i = 0; + size_t i = 0; while (i < session->media_count and pj_stricmp2(&session->media[i]->desc.media, type) != 0) ++i; @@ -616,3 +664,28 @@ void Sdp::getRemoteSdpCryptoFromOffer(const pjmedia_sdp_session* remote_sdp, Cry } } } + +bool Sdp::getOutgoingVideoSettings(map<string, string> &args) const +{ +#ifdef SFL_VIDEO + string codec(getOutgoingVideoCodec()); + if (not codec.empty()) { + const string encoder(libav_utils::encodersMap()[codec]); + if (encoder.empty()) { + DEBUG("Couldn't find encoder for \"%s\"\n", codec.c_str()); + return false; + } else { + args["codec"] = encoder; + args["bitrate"] = getOutgoingVideoField(codec, "bitrate"); + const int payload = getOutgoingVideoPayload(); + std::ostringstream os; + os << payload; + args["payload_type"] = os.str(); + // override with profile-level-id from remote, if present + getProfileLevelID(activeRemoteSession_, args["parameters"], payload); + } + return true; + } +#endif + return false; +} diff --git a/daemon/src/sip/sdp.h b/daemon/src/sip/sdp.h index fb0f9d2eedba1f02f56733d4f550718ef5cf4a73..cfa898ae64aaa8e70514cce9bd43b329487eb426 100644 --- a/daemon/src/sip/sdp.h +++ b/daemon/src/sip/sdp.h @@ -113,10 +113,7 @@ class Sdp { * Returns a string version of the negotiated SDP fields which pertain * to video. */ - std::string getActiveIncomingVideoDescription() const; - std::string getActiveOutgoingVideoCodec() const; - std::string getActiveOutgoingVideoBitrate(const std::string &codec) const; - std::string getActiveOutgoingVideoPayload() const; + std::string getIncomingVideoDescription() const; /* * On building an invite outside a dialog, build the local offer and create the @@ -242,12 +239,19 @@ class Sdp { std::string getAudioCodecName() const; std::string getSessionVideoCodec() const; sfl::AudioCodec* getSessionAudioMedia() const; + // Sets @param settings with appropriate values and returns true if + // we are sending video, false otherwise + bool getOutgoingVideoSettings(std::map<std::string, std::string> &settings) const; private: NON_COPYABLE(Sdp); friend class SDPTest; std::string getLineFromSession(const pjmedia_sdp_session *sess, const std::string &keyword) const; + std::string getOutgoingVideoCodec() const; + std::string getOutgoingVideoField(const std::string &codec, const char *key) const; + int getOutgoingVideoPayload() const; + void getProfileLevelID(const pjmedia_sdp_session *session, std::string &dest, int payload) const; /** * The pool to allocate memory, ownership to SipCall diff --git a/daemon/src/sip/sip_utils.cpp b/daemon/src/sip/sip_utils.cpp index bdcd57542a5971163f42355df615fb8172d75810..d64a2f6c2d6e5dd925717c8eb7982dc6d27b2bc8 100644 --- a/daemon/src/sip/sip_utils.cpp +++ b/daemon/src/sip/sip_utils.cpp @@ -42,6 +42,13 @@ #include <pj/list.h> #include "sip_utils.h" +// for resolveDns +#include <list> +#include <netdb.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + std::string sip_utils::fetchHeaderValue(pjsip_msg *msg, const std::string &field) { @@ -124,3 +131,41 @@ sip_utils::stripSipUriPrefix(std::string& sipUri) if (found != std::string::npos) sipUri.erase(found); } + +/** + * This function looks for '@' and replaces the second part with the corresponding ip address (when possible) + */ +std::string +sip_utils::resolveDns(const std::string &url) +{ + size_t pos; + if ((pos = url.find("@")) == std::string::npos) + return url; + + const std::string hostname = url.substr(pos + 1); + + std::list<std::string> ipList(resolveServerDns(hostname)); + if (not ipList.empty() and ipList.front().size() > 7 ) + return url.substr(0, pos + 1) + ipList.front(); + else + return hostname; +} + +/** + * This function finds the list of IP addresses (when possible) for a given server + */ +std::list<std::string> +sip_utils::resolveServerDns(const std::string &server) +{ + struct hostent *he; + std::list<std::string> ipList; + + if ((he = gethostbyname(server.c_str())) == NULL) + return ipList; + struct in_addr **addr_list = (struct in_addr **) he->h_addr_list; + + for (int i = 0; addr_list[i] != NULL; ++i) + ipList.push_back(inet_ntoa(*addr_list[i])); + + return ipList; +} diff --git a/daemon/src/sip/sip_utils.h b/daemon/src/sip/sip_utils.h index 4d430af97c99fd307eb7e67483cedba6ee128ef9..99c56002cf26a542e17ec6d45ca91efb4174d6fc 100644 --- a/daemon/src/sip/sip_utils.h +++ b/daemon/src/sip/sip_utils.h @@ -33,6 +33,7 @@ #define SIP_UTILS_H_ #include <string> +#include <list> #include <pjsip/sip_msg.h> @@ -50,6 +51,9 @@ namespace sip_utils { void stripSipUriPrefix(std::string& sipUri); std::string parseDisplayName(const char * buffer); + + std::string resolveDns(const std::string &url); + std::list<std::string> resolveServerDns(const std::string &server); } #endif // SIP_UTILS_H_ diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp index 25cf904f7cd15e229f9ac02743d35f7b8c56f706..b0e6d55c71c68945ce50bc5bad4951e187aa55ab 100644 --- a/daemon/src/sip/sipaccount.cpp +++ b/daemon/src/sip/sipaccount.cpp @@ -36,6 +36,7 @@ #include "account_schema.h" #include "sipaccount.h" +#include "sip_utils.h" #include "sipvoiplink.h" #include "config/yamlnode.h" #include "config/yamlemitter.h" @@ -43,7 +44,8 @@ #include "manager.h" #include <pwd.h> #include <sstream> -#include <stdlib.h> +#include <algorithm> +#include <cstdlib> #ifdef SFL_VIDEO #include "video/libav_utils.h" @@ -161,6 +163,7 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter) mapNode->setKeyValue(VIDEO_CODEC_NAME, new ScalarNode(codec[VIDEO_CODEC_NAME])); mapNode->setKeyValue(VIDEO_CODEC_BITRATE, new ScalarNode(codec[VIDEO_CODEC_BITRATE])); mapNode->setKeyValue(VIDEO_CODEC_ENABLED, new ScalarNode(codec[VIDEO_CODEC_ENABLED])); + mapNode->setKeyValue(VIDEO_CODEC_PARAMETERS, new ScalarNode(codec[VIDEO_CODEC_PARAMETERS])); videoCodecs.addNode(mapNode); } #endif @@ -288,6 +291,7 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter) delete node->getValue(VIDEO_CODEC_NAME); delete node->getValue(VIDEO_CODEC_BITRATE); delete node->getValue(VIDEO_CODEC_ENABLED); + delete node->getValue(VIDEO_CODEC_PARAMETERS); delete node; } #endif @@ -327,6 +331,7 @@ void SIPAccount::unserialize(const Conf::MappingNode &mapNode) codec->getValue(VIDEO_CODEC_NAME, &codecMap[VIDEO_CODEC_NAME]); codec->getValue(VIDEO_CODEC_BITRATE, &codecMap[VIDEO_CODEC_BITRATE]); codec->getValue(VIDEO_CODEC_ENABLED, &codecMap[VIDEO_CODEC_ENABLED]); + codec->getValue(VIDEO_CODEC_PARAMETERS, &codecMap[VIDEO_CODEC_PARAMETERS]); videoCodecDetails.push_back(codecMap); } // these must be validated @@ -807,6 +812,14 @@ bool SIPAccount::hostnameMatch(const std::string& hostname) const return hostname == hostname_; } +bool SIPAccount::proxyMatch(const std::string& hostname) const +{ + if (hostname == serviceRoute_) + return true; + const std::list<std::string> ipList(sip_utils::resolveServerDns(serviceRoute_)); + return std::find(ipList.begin(), ipList.end(), hostname) != ipList.end(); +} + std::string SIPAccount::getLoginName() { struct passwd * user_info = getpwuid(getuid()); diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h index 7f5c2e43bcb6e68aa7fefeab070a74bb4d96b8a5..4b0ca9cdc737275d107e413c2fe607a6ec5232fb 100644 --- a/daemon/src/sip/sipaccount.h +++ b/daemon/src/sip/sipaccount.h @@ -252,6 +252,7 @@ class SIPAccount : public Account { bool fullMatch(const std::string& username, const std::string& hostname) const; bool userMatch(const std::string& username) const; bool hostnameMatch(const std::string& hostname) const; + bool proxyMatch(const std::string& hostname) const; /** * Registration flag diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp index a4dfda8b47d2a930e9c3b9882c13f82ab03b92d6..b8b00713e85a22ef2caacefad42ed811a3919280 100644 --- a/daemon/src/sip/sipvoiplink.cpp +++ b/daemon/src/sip/sipvoiplink.cpp @@ -725,43 +725,12 @@ bool isValidIpAddress(const std::string &address) return result != 0; } -/** - * This function look for '@' and replace the second part with the corresponding ip address (when possible) - */ -std::string resolvDns(const std::string& url) -{ - size_t pos; - if ((pos = url.find("@")) == std::string::npos) { - return url; - } - std::string hostname = url.substr(pos+1); - - int i; - struct hostent *he; - struct in_addr **addr_list; - - if ((he = gethostbyname(hostname.c_str())) == NULL) { - return url; - } - - addr_list = (struct in_addr **)he->h_addr_list; - std::list<std::string> ipList; - - for(i = 0; addr_list[i] != NULL; i++) { - ipList.push_back(inet_ntoa(*addr_list[i])); - } - - if (ipList.size() > 0 && ipList.front().size() > 7 ) - return url.substr(0,pos+1)+ipList.front(); - else - return hostname; -} Call *SIPVoIPLink::newOutgoingCall(const std::string& id, const std::string& toUrl) { DEBUG("New outgoing call to %s", toUrl.c_str()); std::string toCpy = toUrl; - std::string resolvedUrl = resolvDns(toUrl); + std::string resolvedUrl = sip_utils::resolveDns(toUrl); DEBUG("URL resolved to %s", resolvedUrl.c_str()); sip_utils::stripSipUriPrefix(toCpy); @@ -893,6 +862,18 @@ SIPVoIPLink::answer(Call *call) call->answer(); } +namespace { +void stopRtpIfCurrent(const std::string &id, SIPCall &call) +{ + if (Manager::instance().isCurrentCall(id)) { + call.getAudioRtp().stop(); +#ifdef SFL_VIDEO + call.getVideoRtp().stop(); +#endif + } +} +} + void SIPVoIPLink::hangup(const std::string& id) { @@ -927,9 +908,7 @@ SIPVoIPLink::hangup(const std::string& id) // Make sure user data is NULL in callbacks inv->mod_data[mod_ua_.id] = NULL; - if (Manager::instance().isCurrentCall(id)) - call->getAudioRtp().stop(); - + stopRtpIfCurrent(id, *call); removeCall(id); } @@ -950,9 +929,7 @@ SIPVoIPLink::peerHungup(const std::string& id) // Make sure user data is NULL in callbacks call->inv->mod_data[mod_ua_.id ] = NULL; - if (Manager::instance().isCurrentCall(id)) - call->getAudioRtp().stop(); - + stopRtpIfCurrent(id, *call); removeCall(id); } @@ -1224,7 +1201,7 @@ dtmfSend(SIPCall &call, char code, const std::string &dtmf) call.getAudioRtp().sendDtmfDigit(code - '0'); return; } else if (dtmf != SIPAccount::SIPINFO_STR) { - WARN("SIPVoIPLink: Unknown DTMF type %s, defaulting to %s instead", + WARN("Unknown DTMF type %s, defaulting to %s instead", dtmf.c_str(), SIPAccount::SIPINFO_STR); } // else : dtmf == SIPINFO @@ -1359,8 +1336,7 @@ SIPVoIPLink::SIPCallClosed(SIPCall *call) { std::string id(call->getCallId()); - if (Manager::instance().isCurrentCall(id)) - call->getAudioRtp().stop(); + stopRtpIfCurrent(id, *call); Manager::instance().peerHungupCall(id); removeCall(id); @@ -1803,7 +1779,7 @@ void update_contact_header(pjsip_regc_cbparam *param, SIPAccount *account) } if (!param or param->contact_cnt == 0) { - WARN("SIPVoIPLink: No contact header in registration callback"); + WARN("No contact header in registration callback"); pj_pool_release(pool); return; } diff --git a/daemon/src/video/libav_utils.cpp b/daemon/src/video/libav_utils.cpp index 52d842e86c77824b1c5187367b16e8bfffdba850..2258ae87e4a24188b5acc146f3227673daab47e2 100644 --- a/daemon/src/video/libav_utils.cpp +++ b/daemon/src/video/libav_utils.cpp @@ -52,7 +52,6 @@ vector<string> installed_video_codecs_; /* application wide mutex to protect concurrent access to avcodec */ ost::Mutex avcodec_lock_; - void findInstalledVideoCodecs() { vector<string> libav_codecs; @@ -73,7 +72,6 @@ void findInstalledVideoCodecs() namespace libav_utils { - vector<string> getVideoCodecList() { if (installed_video_codecs_.empty()) @@ -154,6 +152,9 @@ getDefaultCodecs() codec["name"] = *iter; codec["bitrate"] = DEFAULT_BITRATE; codec["enabled"] = "true"; + // FIXME: make a nicer version of this + if (*iter == "H264") + codec["parameters"] = DEFAULT_H264_PROFILE_LEVEL_ID; result.push_back(codec); } return result; diff --git a/daemon/src/video/libav_utils.h b/daemon/src/video/libav_utils.h index a18714ec1bedffacc31fbe32ddb34ac5057b3fca..b695a66030aa472dbf410d323ac96a5bcdcfefc6 100644 --- a/daemon/src/video/libav_utils.h +++ b/daemon/src/video/libav_utils.h @@ -47,6 +47,8 @@ namespace libav_utils { std::vector<std::map<std::string, std::string> > getDefaultCodecs(); + const char *const DEFAULT_H264_PROFILE_LEVEL_ID = "profile-level-id=428014"; + const char *const MAX_H264_PROFILE_LEVEL_ID = "profile-level-id=640034"; } #endif // __LIBAV_UTILS_H__ diff --git a/daemon/src/video/video_receive_thread.cpp b/daemon/src/video/video_receive_thread.cpp index 48da041d975809b51580d60a9e6457fb72532381..39b12a94756a632b2dfd56c3fc95922af715c202 100644 --- a/daemon/src/video/video_receive_thread.cpp +++ b/daemon/src/video/video_receive_thread.cpp @@ -100,6 +100,18 @@ void VideoReceiveThread::loadSDP() os.close(); } +void VideoReceiveThread::openDecoder() +{ + if (decoderCtx_) + avcodec_close(decoderCtx_); +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 6, 0) + int ret = avcodec_open(decoderCtx_, inputDecoder_); +#else + int ret = avcodec_open2(decoderCtx_, inputDecoder_, NULL); +#endif + EXIT_IF_FAIL(ret == 0, "Could not open codec"); +} + // We do this setup here instead of the constructor because we don't want the // main thread to block while this executes, so it happens in the video thread. void VideoReceiveThread::setup() @@ -162,15 +174,10 @@ void VideoReceiveThread::setup() decoderCtx_ = inputCtx_->streams[streamIndex_]->codec; // find the decoder for the video stream - AVCodec *inputDecoder = avcodec_find_decoder(decoderCtx_->codec_id); - EXIT_IF_FAIL(inputDecoder, "Unsupported codec"); + inputDecoder_ = avcodec_find_decoder(decoderCtx_->codec_id); + EXIT_IF_FAIL(inputDecoder_, "Unsupported codec"); -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 6, 0) - ret = avcodec_open(decoderCtx_, inputDecoder); -#else - ret = avcodec_open2(decoderCtx_, inputDecoder, NULL); -#endif - EXIT_IF_FAIL(ret == 0, "Could not open codec"); + openDecoder(); scaledPicture_ = avcodec_alloc_frame(); EXIT_IF_FAIL(scaledPicture_, "Could not allocate output frame"); @@ -207,7 +214,7 @@ int VideoReceiveThread::interruptCb(void *ctx) } VideoReceiveThread::VideoReceiveThread(const std::string &id, const std::map<string, string> &args) : - args_(args), frameNumber_(0), decoderCtx_(0), rawFrame_(0), + args_(args), frameNumber_(0), inputDecoder_(0), decoderCtx_(0), rawFrame_(0), scaledPicture_(0), streamIndex_(-1), inputCtx_(0), imgConvertCtx_(0), dstWidth_(0), dstHeight_(0), sink_(), receiving_(false), sdpFilename_(), bufferSize_(0), id_(id), interruptCb_(), requestKeyFrameCallback_(0) @@ -261,8 +268,11 @@ void VideoReceiveThread::run() int frameFinished = 0; const int len = avcodec_decode_video2(decoderCtx_, rawFrame_, &frameFinished, &inpacket); - if (len <= 0 and requestKeyFrameCallback_) + if (len <= 0 and requestKeyFrameCallback_) { + openDecoder(); requestKeyFrameCallback_(id_); + usleep(250000); + } // we want our rendering code to be called by the shm_sink, // because it manages the shared memory synchronization diff --git a/daemon/src/video/video_receive_thread.h b/daemon/src/video/video_receive_thread.h index e0d03a4a7ee73c9998788e6a1f30d21d2a3cfab9..ac9efa098bed3cc3ad2c025eb22107172eb7c66c 100644 --- a/daemon/src/video/video_receive_thread.h +++ b/daemon/src/video/video_receive_thread.h @@ -60,6 +60,7 @@ class VideoReceiveThread : public ost::Thread { /* These variables should be used in thread (i.e. run()) only! */ /*-------------------------------------------------------------*/ + AVCodec *inputDecoder_; AVCodecContext *decoderCtx_; AVFrame *rawFrame_; AVFrame *scaledPicture_; @@ -76,6 +77,7 @@ class VideoReceiveThread : public ost::Thread { size_t bufferSize_; const std::string id_; void setup(); + void openDecoder(); void createScalingContext(); void loadSDP(); void fill_buffer(void *data); diff --git a/daemon/src/video/video_rtp_session.cpp b/daemon/src/video/video_rtp_session.cpp index 3e3f403db775c1802bade86d03c50eefbcba3575..2976598dcaa3333d0632f3483eaf71b75923638a 100644 --- a/daemon/src/video/video_rtp_session.cpp +++ b/daemon/src/video/video_rtp_session.cpp @@ -36,7 +36,6 @@ #include "video_receive_thread.h" #include "sip/sdp.h" #include "sip/sipvoiplink.h" -#include "libav_utils.h" #include "manager.h" #include "logger.h" @@ -52,7 +51,7 @@ VideoRtpSession::VideoRtpSession(const string &callID, const map<string, string> void VideoRtpSession::updateSDP(const Sdp &sdp) { - string desc(sdp.getActiveIncomingVideoDescription()); + string desc(sdp.getIncomingVideoDescription()); // if port has changed if (desc != rxArgs_["receiving_sdp"]) { rxArgs_["receiving_sdp"] = desc; @@ -84,21 +83,8 @@ void VideoRtpSession::updateSDP(const Sdp &sdp) receiving_ = false; } - string codec(sdp.getActiveOutgoingVideoCodec()); - if (not codec.empty()) { - const string encoder(libav_utils::encodersMap()[codec]); - if (encoder.empty()) { - DEBUG("Couldn't find encoder for \"%s\"\n", codec.c_str()); - sending_ = false; - } else { - txArgs_["codec"] = encoder; - txArgs_["bitrate"] = sdp.getActiveOutgoingVideoBitrate(codec); - } - } else { - sending_ = false; - } - - txArgs_["payload_type"] = sdp.getActiveOutgoingVideoPayload();; + if (sending_) + sending_ = sdp.getOutgoingVideoSettings(txArgs_); } void VideoRtpSession::updateDestination(const string &destination, @@ -159,7 +145,10 @@ void VideoRtpSession::stop() void VideoRtpSession::forceKeyFrame() { - sendThread_->forceKeyFrame(); + if (sendThread_.get()) + sendThread_->forceKeyFrame(); + else + ERROR("Video sending thread is NULL"); } } // end namespace sfl_video diff --git a/daemon/src/video/video_send_thread.cpp b/daemon/src/video/video_send_thread.cpp index 1848e4e3c30d9b8208bf659772cb919dfe933146..622a0d5338495af6f419954ef57da560143207d6 100644 --- a/daemon/src/video/video_send_thread.cpp +++ b/daemon/src/video/video_send_thread.cpp @@ -121,6 +121,53 @@ void VideoSendThread::prepareEncoderContext(AVCodec *encoder) // encoderCtx_->flags |= CODEC_FLAG_GLOBAL_HEADER; } +namespace { +void +extractProfileLevelID(const std::string ¶meters, AVCodecContext *ctx) +{ + // From RFC3984: + // If no profile-level-id is present, the Baseline Profile without + // additional constraints at Level 1 MUST be implied. + ctx->profile = FF_PROFILE_H264_BASELINE; + ctx->level = 0xa; + // ctx->level = 0x0d; // => 13 aka 1.3 + if (parameters.empty()) + return; + + const std::string target("profile-level-id="); + size_t needle = parameters.find(target); + if (needle == std::string::npos) + return; + + needle += target.length(); + const size_t id_length = 6; /* digits */ + const std::string profileLevelID(parameters.substr(needle, id_length)); + if (profileLevelID.length() != id_length) + return; + + int result; + std::stringstream ss; + ss << profileLevelID; + ss >> std::hex >> result; + // profile-level id consists of three bytes + const unsigned char profile_idc = result >> 16; // 42xxxx -> 42 + const unsigned char profile_iop = ((result >> 8) & 0xff); // xx80xx -> 80 + ctx->level = result & 0xff; // xxxx0d -> 0d + switch (profile_idc) { + case FF_PROFILE_H264_BASELINE: + // check constraint_set_1_flag + ctx->profile |= (profile_iop & 0x40) >> 6 ? FF_PROFILE_H264_CONSTRAINED : 0; + break; + case FF_PROFILE_H264_HIGH_10: + case FF_PROFILE_H264_HIGH_422: + case FF_PROFILE_H264_HIGH_444_PREDICTIVE: + // check constraint_set_3_flag + ctx->profile |= (profile_iop & 0x10) >> 4 ? FF_PROFILE_H264_INTRA : 0; + break; + } + DEBUG("Using profile %x and level %d", ctx->profile, ctx->level); +} +} void VideoSendThread::setup() { @@ -191,12 +238,11 @@ void VideoSendThread::setup() /* let x264 preset override our encoder settings */ if (args_["codec"] == "libx264") { - forcePresetX264(); // FIXME: this should be parsed from the fmtp:profile-level-id // attribute of our peer, it will determine what profile and // level we are sending (i.e. that they can accept). - encoderCtx_->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE; - encoderCtx_->level = 0x0d; // => 13 aka 1.3 + extractProfileLevelID(args_["parameters"], encoderCtx_); + forcePresetX264(); } scaledPicture_ = avcodec_alloc_frame(); diff --git a/gnome/configure.ac b/gnome/configure.ac index 4254db319b6cb2ccbe825dc5d13704487915e169..81134b1679c3aa47f5665744fe74c1b9894334bf 100644 --- a/gnome/configure.ac +++ b/gnome/configure.ac @@ -35,17 +35,15 @@ dnl Video is default-disabled AC_ARG_ENABLE([video], AS_HELP_STRING([--enable-video], [Enable video])) AS_IF([test "x$enable_video" = "xyes"], [ AC_DEFINE(SFL_VIDEO, [], [Video support enabled]) - PKG_CHECK_MODULES(CLUTTER, clutter-1.0) PKG_CHECK_MODULES(CLUTTERGTK, clutter-gtk-1.0) ]); AM_CONDITIONAL(SFL_VIDEO, test "x$enable_video" = "xyes") -# Check for gtk+-3.0, otherwise check for gtk+-2.0 -PKG_CHECK_MODULES(GTK, gtk+-3.0, - [PKG_CHECK_MODULES(GTK, gtk+-2.0, , - [PKG_CHECK_MODULES(GTHREAD, gthread-2.0)], +# Check for gtk+-3.0, otherwise check for gtk+-2.0 (and gthread) +PKG_CHECK_MODULES(GTK, gtk+-3.0, [AC_MSG_NOTICE(Using gtk+-3.0)], + [PKG_CHECK_MODULES(GTK, gtk+-2.0, [PKG_CHECK_MODULES(GTHREAD, gthread-2.0)], [AC_MSG_ERROR(gtk-2 not found)])]) PKG_CHECK_MODULES(GCONF, gconf-2.0) diff --git a/gnome/src/config/audioconf.c b/gnome/src/config/audioconf.c index 62c37cab2042a0176bc599ca6e0c52e505e2d3cb..339340e01e94d39eb0fda1970cc979dcca18f5f1 100644 --- a/gnome/src/config/audioconf.c +++ b/gnome/src/config/audioconf.c @@ -518,6 +518,9 @@ audiocodecs_box(const account_t *account) // Create codec tree view with list store codecTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(codecStore)); + /* The list store model will be destroyed automatically with the view */ + g_object_unref(G_OBJECT(codecStore)); + // Get tree selection manager GtkTreeSelection *treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(codecTreeView)); g_signal_connect(G_OBJECT(treeSelection), "changed", @@ -547,7 +550,6 @@ audiocodecs_box(const account_t *account) treeViewColumn = gtk_tree_view_column_new_with_attributes(_("Bitrate"), renderer, "text", COLUMN_CODEC_BITRATE, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(codecTreeView), treeViewColumn); - g_object_unref(G_OBJECT(codecStore)); gtk_container_add(GTK_CONTAINER(scrolledWindow), codecTreeView); // Create button box diff --git a/gnome/src/config/videoconf.c b/gnome/src/config/videoconf.c index 6f1e030131ace01a173eac0cf55a812fbe3fca1f..51e14cf6ec0ed45cfca7d492a61c4d412288b0e0 100644 --- a/gnome/src/config/videoconf.c +++ b/gnome/src/config/videoconf.c @@ -62,6 +62,7 @@ enum { COLUMN_CODEC_ACTIVE, COLUMN_CODEC_NAME, COLUMN_CODEC_BITRATE, + COLUMN_CODEC_PARAMETERS, CODEC_COLUMN_COUNT }; @@ -164,12 +165,14 @@ preferences_dialog_fill_codec_list(account_t *acc) GtkTreeIter iter; gtk_list_store_append(codecStore, &iter); const gchar *bitrate = g_hash_table_lookup(c, "bitrate"); + const gchar *parameters = g_hash_table_lookup(c, "parameters"); const gboolean is_active = !g_strcmp0(g_hash_table_lookup(c, "enabled"), "true"); const gchar *name = g_hash_table_lookup(c, "name"); gtk_list_store_set(codecStore, &iter, COLUMN_CODEC_ACTIVE, is_active, COLUMN_CODEC_NAME, name, - COLUMN_CODEC_BITRATE, bitrate, -1); + COLUMN_CODEC_BITRATE, bitrate, + COLUMN_CODEC_PARAMETERS, parameters, -1); } } g_ptr_array_free(vcodecs, TRUE); @@ -198,6 +201,12 @@ video_codec_set_bitrate(GHashTable *codec, const gchar *bitrate) g_hash_table_replace(codec, g_strdup("bitrate"), g_strdup(bitrate)); } +static void +video_codec_set_parameters(GHashTable *codec, const gchar *parameters) +{ + g_hash_table_replace(codec, g_strdup("parameters"), g_strdup(parameters)); +} + static GHashTable * video_codec_list_get_by_name(GPtrArray *vcodecs, const gchar *name) { @@ -403,6 +412,46 @@ bitrate_edited_cb(GtkCellRenderer *renderer UNUSED, gchar *path, gchar *new_text } +static void +parameters_edited_cb(GtkCellRenderer *renderer UNUSED, gchar *path, gchar *new_text, gpointer data) +{ + account_t *acc = (account_t*) data; + + if (!acc) { + ERROR("No account selected"); + return; + } + + if (strlen(new_text) == 0) + return; + + // Get path of edited codec + GtkTreePath *tree_path = gtk_tree_path_new_from_string(path); + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(codecTreeView)); + GtkTreeIter iter; + gtk_tree_model_get_iter(model, &iter, tree_path); + gtk_tree_path_free(tree_path); + gchar *name = NULL; + gtk_tree_model_get(model, &iter, COLUMN_CODEC_NAME, &name, -1); + + GPtrArray *vcodecs = dbus_get_video_codecs(acc->accountID); + if (!vcodecs) + return; + + gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_CODEC_PARAMETERS, new_text, -1); + + GHashTable *codec = video_codec_list_get_by_name(vcodecs, name); + if (codec) { + DEBUG("Setting new parameters \"%s\" for %s", new_text, name); + video_codec_set_parameters(codec, new_text); + dbus_set_video_codecs(acc->accountID, vcodecs); + } else { + ERROR("Could not find codec %s", name); + } + g_ptr_array_free(vcodecs, TRUE); +} + + GtkWidget * videocodecs_box(account_t *acc) { @@ -424,6 +473,9 @@ videocodecs_box(account_t *acc) // Create codec tree view with list store codecTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(codecStore)); + /* The list store model will be destroyed automatically with the view */ + g_object_unref(G_OBJECT(codecStore)); + // Get tree selection manager GtkTreeSelection *treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(codecTreeView)); g_signal_connect(G_OBJECT(treeSelection), "changed", @@ -450,7 +502,13 @@ videocodecs_box(account_t *acc) treeViewColumn = gtk_tree_view_column_new_with_attributes(_("Bitrate (kbps)"), renderer, "text", COLUMN_CODEC_BITRATE, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(codecTreeView), treeViewColumn); - g_object_unref(G_OBJECT(codecStore)); + /* Parameters column */ + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, "editable", TRUE, NULL); + g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(parameters_edited_cb), acc); + treeViewColumn = gtk_tree_view_column_new_with_attributes(_("Parameters"), renderer, "text", COLUMN_CODEC_PARAMETERS, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(codecTreeView), treeViewColumn); + gtk_container_add(GTK_CONTAINER(scrolledWindow), codecTreeView); // Create button box @@ -731,12 +789,10 @@ fill_devices() gtk_widget_show_all(v4l2_hbox); gtk_widget_hide(v4l2_nodev); gtk_widget_set_sensitive(preview_button, TRUE); - } else { - if (GTK_IS_WIDGET(v4l2_hbox)) { - gtk_widget_hide(v4l2_hbox); - gtk_widget_show(v4l2_nodev); - gtk_widget_set_sensitive(preview_button, FALSE); - } + } else if (GTK_IS_WIDGET(v4l2_hbox)) { + gtk_widget_hide(v4l2_hbox); + gtk_widget_show(v4l2_nodev); + gtk_widget_set_sensitive(preview_button, FALSE); } } @@ -750,7 +806,6 @@ video_device_event_cb(DBusGProxy *proxy UNUSED, void * foo UNUSED) static GtkWidget * v4l2_box() { - DEBUG("%s", __PRETTY_FUNCTION__); GtkWidget *ret = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); v4l2_nodev = gtk_label_new(_("No devices found")); diff --git a/gnome/src/dbus/configurationmanager-introspec.xml b/gnome/src/dbus/configurationmanager-introspec.xml index 3f785278fe528000caa7aa29681d1abece1e77f9..7efc7a85f89c6cea1bbbc03e28041415762aa8e6 100644 --- a/gnome/src/dbus/configurationmanager-introspec.xml +++ b/gnome/src/dbus/configurationmanager-introspec.xml @@ -185,14 +185,17 @@ </arg> </method> + <method name="registerAllAccounts" tp:name-for-bindings="registerAllAccounts"> + <tp:docstring> + Send account registration (REGISTER) for all accounts, even if they are not enabled. + </tp:docstring> + </method> + <method name="sendRegister" tp:name-for-bindings="sendRegister"> <tp:docstring> Send account registration (REGISTER) to the registrar. + Register the account if enable=true, unregister if enable=false. </tp:docstring> - Register the account if enable=true, unregister if enable=false. - - @param[in] input accountID - --> <arg type="s" name="accountID" direction="in"> <tp:docstring> The account ID diff --git a/gnome/src/dbus/dbus.c b/gnome/src/dbus/dbus.c index d63710a0ec9753d1b3741014241362cf8467e5e3..b43a40e19e782ef3579b727896385fed13ec105b 100644 --- a/gnome/src/dbus/dbus.c +++ b/gnome/src/dbus/dbus.c @@ -1045,16 +1045,8 @@ dbus_account_list() GError *error = NULL; char **array = NULL; - if (!org_sflphone_SFLphone_ConfigurationManager_get_account_list(config_proxy, &array, &error)) { - if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) - ERROR("Caught remote method (get_account_list) exception %s: %s", - dbus_g_error_get_name(error), error->message); - else - ERROR("Error while calling get_account_list: %s", error->message); - - g_error_free(error); - } else - DEBUG("DBus called get_account_list() on ConfigurationManager"); + org_sflphone_SFLphone_ConfigurationManager_get_account_list(config_proxy, &array, &error); + check_error(error); return array; } @@ -1065,16 +1057,8 @@ dbus_get_account_details(const gchar *accountID) GError *error = NULL; GHashTable *details = NULL; - if (!org_sflphone_SFLphone_ConfigurationManager_get_account_details(config_proxy, accountID, &details, &error)) { - if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) - ERROR("Caught remote method exception %s: %s", - dbus_g_error_get_name(error), error->message); - else - ERROR("Error while calling get_account_details: %s", - error->message); - - g_error_free(error); - } + org_sflphone_SFLphone_ConfigurationManager_get_account_details(config_proxy, accountID, &details, &error); + check_error(error); return details; } @@ -1094,18 +1078,9 @@ dbus_get_credentials(account_t *a) { g_assert(a); GError *error = NULL; - if (org_sflphone_SFLphone_ConfigurationManager_get_credentials(config_proxy, a->accountID, - &a->credential_information, &error)) - return; - - if (error->domain == DBUS_GERROR && - error->code == DBUS_GERROR_REMOTE_EXCEPTION) - ERROR("Caught remote method (get_account_details) exception %s: %s", - dbus_g_error_get_name(error), error->message); - else - ERROR("Error while calling get_account_details: %s", error->message); - - g_error_free(error); + org_sflphone_SFLphone_ConfigurationManager_get_credentials(config_proxy, + a->accountID, &a->credential_information, &error); + check_error(error); } GHashTable * @@ -1114,16 +1089,8 @@ dbus_get_ip2_ip_details(void) GError *error = NULL; GHashTable *details = NULL; - if (!org_sflphone_SFLphone_ConfigurationManager_get_ip2_ip_details(config_proxy, &details, &error)) { - if (error->domain == DBUS_GERROR && - error->code == DBUS_GERROR_REMOTE_EXCEPTION) - ERROR("Caught remote method (get_ip2_ip_details) exception %s: %s", - dbus_g_error_get_name(error), error->message); - else - ERROR("Error while calling get_ip2_ip_details: %s", error->message); - - g_error_free(error); - } + org_sflphone_SFLphone_ConfigurationManager_get_ip2_ip_details(config_proxy, &details, &error); + check_error(error); return details; } @@ -1319,15 +1286,8 @@ dbus_get_audio_plugin_list() gchar **array = NULL; GError *error = NULL; - if (!org_sflphone_SFLphone_ConfigurationManager_get_audio_plugin_list(config_proxy, &array, &error)) { - if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) - ERROR("Caught remote method (get_output_plugin_list) exception" - "%s: %s", dbus_g_error_get_name(error), error->message); - else - ERROR("Error while calling get_out_plugin_list: %s", error->message); - - g_error_free(error); - } + org_sflphone_SFLphone_ConfigurationManager_get_audio_plugin_list(config_proxy, &array, &error); + check_error(error); return array; } @@ -2054,15 +2014,8 @@ dbus_get_all_ip_interface(void) GError *error = NULL; gchar **array = NULL; - if (!org_sflphone_SFLphone_ConfigurationManager_get_all_ip_interface(config_proxy, &array, &error)) { - if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) - ERROR("Caught remote method (get_all_ip_interface) exception %s: %s", dbus_g_error_get_name(error), error->message); - else - ERROR("%s", error->message); - - g_error_free(error); - } else - DEBUG("DBus called get_all_ip_interface() on ConfigurationManager"); + org_sflphone_SFLphone_ConfigurationManager_get_all_ip_interface(config_proxy, &array, &error); + check_error(error); return array; } @@ -2073,15 +2026,8 @@ dbus_get_all_ip_interface_by_name(void) GError *error = NULL; gchar **array = NULL; - if (!org_sflphone_SFLphone_ConfigurationManager_get_all_ip_interface_by_name(config_proxy, &array, &error)) { - if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) - ERROR("Caught remote method (get_all_ip_interface) exception %s: %s", - dbus_g_error_get_name(error), error->message); - else - ERROR("%s", error->message); - - g_error_free(error); - } + org_sflphone_SFLphone_ConfigurationManager_get_all_ip_interface_by_name(config_proxy, &array, &error); + check_error(error); return array; } @@ -2092,15 +2038,8 @@ dbus_get_shortcuts(void) GError *error = NULL; GHashTable *shortcuts = NULL; - if (!org_sflphone_SFLphone_ConfigurationManager_get_shortcuts(config_proxy, &shortcuts, &error)) { - if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) - ERROR("Caught remote method (get_shortcuts) exception %s: %s", - dbus_g_error_get_name(error), error->message); - else - ERROR("%s", error->message); - - g_error_free(error); - } + org_sflphone_SFLphone_ConfigurationManager_get_shortcuts(config_proxy, &shortcuts, &error); + check_error(error); return shortcuts; } diff --git a/gnome/src/dbus/video_controls-introspec.xml b/gnome/src/dbus/video_controls-introspec.xml index ef99d1df7aa39747a7d0fb08f8975a8d72fd5351..73f6d7e8d893eb5a7dc0f2c84748810dfcc21c06 100644 --- a/gnome/src/dbus/video_controls-introspec.xml +++ b/gnome/src/dbus/video_controls-introspec.xml @@ -98,6 +98,7 @@ <tp:docstring>Sets a vector of hashtables describing codecs and their parameters for a given account, one hashtable per codec</tp:docstring> <arg type="s" name="accountID" direction="in"> </arg> + <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="VectorMapStringString"/> <arg type="aa{ss}" name="details" direction="in"> </arg> </method> diff --git a/gnome/src/mainwindow.c b/gnome/src/mainwindow.c index aec0fce31253a0c74a616b79f6e874cd79344d26..c085582fe841ab6c112500debc91e5e02a5819bf 100644 --- a/gnome/src/mainwindow.c +++ b/gnome/src/mainwindow.c @@ -292,7 +292,7 @@ create_main_window() int messaging_height = eel_gconf_get_integer(CONF_MESSAGING_HEIGHT); set_message_tab_height(GTK_PANED(vpaned),messaging_height); - + gtk_widget_show (vpaned); gtk_box_pack_start(GTK_BOX(vbox), vpaned, TRUE, TRUE, 0); @@ -301,7 +301,7 @@ create_main_window() history_tab->mainwidget = history_vbox; gtk_box_set_homogeneous(GTK_BOX(history_vbox), FALSE); gtk_box_pack_start(GTK_BOX(history_vbox), history_tab->tree, TRUE, TRUE, 0); - + /* Add tree views */ gtk_box_pack_start(GTK_BOX(vbox), contacts_tab->tree, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), history_vbox, TRUE, TRUE, 0); diff --git a/gnome/src/messaging/message_tab.c b/gnome/src/messaging/message_tab.c index 026569ac6bb206f757bf4f9e72b8b0cbc29034c0..e98bfa9933e18bfeff556dd50d5b282bf000942b 100644 --- a/gnome/src/messaging/message_tab.c +++ b/gnome/src/messaging/message_tab.c @@ -229,7 +229,7 @@ on_cursor_motion(GtkTextView *view UNUSED, GdkEvent *event, gpointer data) start_real = end_match_b; end_real = cursor_pos ; } - + /*Get the word under cursor*/ gchar* text = gtk_text_buffer_get_text(((message_tab*) data)->buffer,&start_real,&end_real,FALSE); @@ -306,7 +306,7 @@ append_message(message_tab* self, const gchar* name, const gchar* message) gtk_text_buffer_insert ( self->buffer, &new_end, "\n" , -1 ); gtk_text_buffer_get_end_iter( self->buffer, &new_end ); gtk_text_view_scroll_to_iter( self->view , &new_end,FALSE,0,0,FALSE ); - + start_link = NULL; end_link = NULL; } @@ -467,7 +467,7 @@ create_messaging_tab(callable_obj_t* call) else label_text = call->_peer_number ; message_tab* self = create_messaging_tab_common(call->_callID,label_text); - + self->call = call; self->conf = NULL; return self; @@ -484,4 +484,4 @@ create_messaging_tab_conf(conference_obj_t* call) return self; } return NULL; -} \ No newline at end of file +} diff --git a/gnome/src/uimanager.c b/gnome/src/uimanager.c index abfed466e530182ca15392c54dbb64ae223ad23d..ac03e92269af85cea0ebe599e15d10eb4fa550bc 100644 --- a/gnome/src/uimanager.c +++ b/gnome/src/uimanager.c @@ -103,6 +103,8 @@ static GtkWidget * imToolbar_; static GtkWidget * editable_num_; static GtkWidget * edit_dialog_; +// GtkToolItem *separator_; + static void remove_from_toolbar(GtkWidget *widget) { @@ -440,9 +442,6 @@ update_actions() gtk_widget_set_sensitive(historyButton_, TRUE); } - GtkToolItem *separator = gtk_separator_tool_item_new(); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar_), separator, -1); - // If addressbook support has been enabled and all addressbooks are loaded, display the icon if (addrbook && addrbook->is_ready() && addressbook_config_load_parameters()->enable) { @@ -1693,6 +1692,7 @@ create_toolbar_actions(GtkUIManager *ui) muteWidget_ = get_widget(ui, "/ToolbarActions/MuteToolbar"); imToolbar_ = get_widget(ui, "/ToolbarActions/InstantMessagingToolbar"); historyButton_ = get_widget(ui, "/ToolbarActions/HistoryToolbar"); +// separator_ = gtk_separator_tool_item_new(); if (addrbook) contactButton_ = get_widget(ui, "/ToolbarActions/AddressbookToolbar"); diff --git a/kde b/kde index 430e7cb1469ca9ebcd124315608f901d6a2cb57f..39ec90aec140f3184b298c6de670183421e66bff 160000 --- a/kde +++ b/kde @@ -1 +1 @@ -Subproject commit 430e7cb1469ca9ebcd124315608f901d6a2cb57f +Subproject commit 39ec90aec140f3184b298c6de670183421e66bff diff --git a/plugins/addressbook/evolution/eds.c b/plugins/addressbook/evolution/eds.c index a36efcbcdbaeb99ef9ae2b3ebcd21e82dee76039..508fc238ef9caf3d1f5f98dfc4459d710ab05765 100644 --- a/plugins/addressbook/evolution/eds.c +++ b/plugins/addressbook/evolution/eds.c @@ -36,13 +36,17 @@ * as that of the covered work. */ +#include "config.h" + #include <glib.h> #include <string.h> #include <pango/pango.h> #include "eds.h" +#if EDS_CHECK_VERSION(3,5,3) +#include <libedataserver/libedataserver.h> +#else #include <libedataserver/e-source.h> - -#include "config.h" +#endif /** * Structure used to store search callback and data diff --git a/plugins/addressbook/evolution/eds.h b/plugins/addressbook/evolution/eds.h index 5bbf71e1af469ff4049cb08d9a6f1c72a681d584..a905dd20f91877240979d020e8eab8f4f17f2787 100644 --- a/plugins/addressbook/evolution/eds.h +++ b/plugins/addressbook/evolution/eds.h @@ -40,7 +40,14 @@ #include <glib.h> #include <gdk-pixbuf/gdk-pixbuf.h> + +#include <libedataserver/eds-version.h> + +#if EDS_CHECK_VERSION(3,5,3) +#include <libebook/libebook.h> +#else #include <libebook/e-book.h> +#endif #include "addressbook.h" diff --git a/tools/build-package.sh b/tools/build-package.sh index 327ba8987ddc84e0f0a0d3c83260938b909ac89b..b68e25193f7f448f9c055d09e7b77e94d899eab7 100755 --- a/tools/build-package.sh +++ b/tools/build-package.sh @@ -46,10 +46,11 @@ if [ -d "sflphone" ]; then exit 1 fi -# Anonymous git http access -git clone http://sflphone.org/git/sflphone.git +# Anonymous git http access, also fetch KDE +git clone http://sflphone.org/git/sflphone.git --recursive cd sflphone git checkout origin/release -b release +git submodule update --init # Get system parameters arch_flag=`getconf -a|grep LONG_BIT | sed -e 's/LONG_BIT\s*//'` diff --git a/tools/build-system/launch-build-machine-jenkins.sh b/tools/build-system/launch-build-machine-jenkins.sh new file mode 100755 index 0000000000000000000000000000000000000000..60b6ea698ce1bdc0393160b450e0aa8de3edf087 --- /dev/null +++ b/tools/build-system/launch-build-machine-jenkins.sh @@ -0,0 +1,270 @@ +#!/bin/bash +##################################################### +# File Name: launch-build-machine-jenkins.sh +# +# Purpose : +# +# Author: Julien Bonjean (julien@bonjean.info) +# +# Creation Date: 2009-10-20 +# Last Modified: 2010-04-22 16:42:57 -0400 +##################################################### + +set -x + +# . `dirname $0`/setenv.sh + +IS_RELEASE= +VERSION_INDEX="1" +IS_KDE_CLIENT= +DO_PUSH=1 +DO_LOGGING=1 +DO_UPLOAD=1 +SNAPSHOT_TAG=`date +%Y%m%d` +TAG_NAME_PREFIX= +VERSION_NUMBER="1.1.0" + +LAUNCHPAD_PACKAGES="sflphone-client-kde" #("sflphone-common" "sflphone-client-kde" "sflphone-plugins") + +echo +echo " /***********************\\" +echo " | SFLPhone build system |" +echo " \\***********************/" +echo + +for PARAMETER in $* +do + case ${PARAMETER} in + --help) + echo + echo "Options :" + echo " --skip-push" + echo " --skip-upload" + echo " --kde-client" + echo " --no-logging" + echo " --release" + echo " --version-index=[1,2,...]" + echo + exit 0;; + --skip-push) + unset DO_PUSH;; + --skip-upload) + unset DO_UPLOAD;; + --kde-client) + IS_KDE_CLIENT=1;; + --no-logging) + unset DO_LOGGING;; + --release) + IS_RELEASE=1;; + --version-index=*) + VERSION_INDEX=(${PARAMETER##*=});; + *) + echo "Unknown parameter : ${PARAMETER}" + exit -1;; + esac +done + +######################### +# LAUNCHPAD +######################### + +# change to working directory +cd ${LAUNCHPAD_DIR} + +if [ "$?" -ne "0" ]; then + echo " !! Cannot cd to launchpad directory" + exit -1 +fi + +# logging +if [ ${DO_LOGGING} ]; then + + rm -f ${ROOT_DIR}/packaging.log >/dev/null 2>&1 + + # open file descriptor + exec 3<> ${ROOT_DIR}/packaging.log + + # redirect outputs (stdout & stderr) + exec 1>&3 + exec 2>&3 +fi + +if [ ${RELEASE_MODE} ]; then + echo "Release mode" +else + echo "Snapshot mode" +fi + +if [ ${IS_KDE_CLIENT} ]; then + TAG_NAME_PREFIX="kde." +fi + +######################### +# COMMON PART +######################### + +cd ${REFERENCE_REPOSITORY} + +echo "Update reference sources" +if [ ${IS_RELEASE} ]; then + git checkout . && git checkout -f release && git pull +else + git checkout . && git checkout -f master && git pull +fi + +echo "Retrieve build info" +# retrieve info we may need +if [ ${IS_KDE_CLIENT} ]; then + TAG_NAME_PREFIX="kde." + LAUNCHPAD_PACKAGES=( "sflphone-client-kde" ) +fi +CURRENT_RELEASE_TAG_NAME=`git describe --tags --abbrev=0` +PREVIOUS_RELEASE_TAG_NAME=`git describe --tags --abbrev=0 ${CURRENT_RELEASE_TAG_NAME}^` +CURRENT_RELEASE_COMMIT_HASH=`git show --pretty=format:"%H" -s ${CURRENT_RELEASE_TAG_NAME} | tail -n 1` +PREVIOUS_RELEASE_COMMIT_HASH=`git show --pretty=format:"%H" -s ${PREVIOUS_RELEASE_TAG_NAME} | tail -n 1` +CURRENT_COMMIT=`git show --pretty=format:"%H" -s | tail -n 1` +CURRENT_RELEASE_TYPE=${CURRENT_RELEASE_TAG_NAME##*.} +PREVIOUS_RELEASE_TYPE=${PREVIOUS_RELEASE_TAG_NAME##*.} +if [ ${IS_KDE_CLIENT} ]; then + CURRENT_RELEASE_VERSION=${CURRENT_RELEASE_TAG_NAME%.*} + CURRENT_RELEASE_VERSION=${CURRENT_RELEASE_VERSION#*.} + PREVIOUS_VERSION=${PREVIOUS_RELEASE_TAG_NAME%.*} + PREVIOUS_VERSION=${PREVIOUS_VERSION#*.} +else + CURRENT_RELEASE_VERSION=${CURRENT_RELEASE_TAG_NAME} + PREVIOUS_VERSION=${PREVIOUS_RELEASE_TAG_NAME} +fi + +cd ${LAUNCHPAD_DIR} + +COMMIT_HASH_BEGIN="" +COMMIT_HASH_END="" +SOFTWARE_VERSION="" +LAUNCHPAD_CONF_PREFIX="" + +if [ ${IS_RELEASE} ]; then + SOFTWARE_VERSION="${CURRENT_RELEASE_VERSION}" + COMMIT_HASH_BEGIN="${PREVIOUS_RELEASE_COMMIT_HASH}" + LAUNCHPAD_CONF_PREFIX="sflphone-testing" +else + # SOFTWARE_VERSION="${VERSION_NUMBER}-rc${SNAPSHOT_TAG}" + SOFTWARE_VERSION="${VERSION_NUMBER}-rc20120730" + COMMIT_HASH_BEGIN="${CURRENT_RELEASE_COMMIT_HASH}" + LAUNCHPAD_CONF_PREFIX="sflphone-nightly" +fi + +VERSION="${SOFTWARE_VERSION}~ppa${VERSION_INDEX}~SYSTEM" + +echo "Clean build directory" +git clean -f -x ${LAUNCHPAD_DIR}/* >/dev/null + +get_dir_name() { + case $1 in + sflphone-common) + echo daemon + ;; + sflphone-plugins) + echo plugins + ;; + sflphone-client-gnome) + echo gnome + ;; + sflphone-client-kde) + echo kde + ;; + *) + exit 1 + ;; + esac +} + +for LAUNCHPAD_PACKAGE in ${LAUNCHPAD_PACKAGES[*]} +do + echo " Package: ${LAUNCHPAD_PACKAGE}" + + echo " --> Clean old sources" + git clean -f -x ${LAUNCHPAD_DIR}/${LAUNCHPAD_PACKAGE}/* >/dev/null + + DEBIAN_DIR="${LAUNCHPAD_DIR}/${LAUNCHPAD_PACKAGE}/debian" + + echo " --> Clean debian directory" + git checkout ${DEBIAN_DIR} + + echo " --> Retrieve new sources" + DIRNAME=`get_dir_name ${LAUNCHPAD_PACKAGE}` + cp -r ${REFERENCE_REPOSITORY}/${DIRNAME}/* ${LAUNCHPAD_DIR}/${LAUNCHPAD_PACKAGE} + + echo " --> Update software version number (${SOFTWARE_VERSION})" + echo "${SOFTWARE_VERSION}" > ${LAUNCHPAD_DIR}/${LAUNCHPAD_PACKAGE}/VERSION + + echo " --> Update debian changelog" + +cat << END > ${WORKING_DIR}/sfl-git-dch.conf +WORKING_DIR="${REFERENCE_REPOSITORY}" +SOFTWARE="${LAUNCHPAD_PACKAGE}" +VERSION="${VERSION}" +DISTRIBUTION="SYSTEM" +CHANGELOG_FILE="${DEBIAN_DIR}/changelog" +COMMIT_HASH_BEGIN="${COMMIT_HASH_BEGIN}" +COMMIT_HASH_END="${COMMIT_HASH_END}" +IS_RELEASE=${IS_RELEASE} +export DEBFULLNAME="Emmanuel Milou" +export DEBEMAIL="emmanuel.milou@savoirfairelinux.com" +export EDITOR="echo" +END + + ${WORKING_DIR}/sfl-git-dch-2.sh ${WORKING_DIR}/sfl-git-dch.conf ${REFERENCE_REPOSITORY}/${DIRNAME}/ + if [ "$?" -ne "0" ]; then + echo "!! Cannot update debian changelogs" + exit -1 + fi + + if [ "${LAUNCHPAD_PACKAGE}" == "sflphone-client-kde" ]; then + version_kde=$(echo ${VERSION} | grep -e '[0-9]*\.[0-9.]*' -o | head -n1) + sed -i -e "s/Standards-Version: [0-9.A-Za-z]*/Standards-Version: ${version_kde}/" ${LAUNCHPAD_DIR}/${LAUNCHPAD_PACKAGE}/debian/control + tar -C ${LAUNCHPAD_DIR}/ -cjf ${LAUNCHPAD_DIR}/sflphone-client-kde_${version_kde}.orig.tar.bz2 ${LAUNCHPAD_PACKAGE} + fi + + rm -f ${WORKING_DIR}/sfl-git-dch.conf >/dev/null 2>&1 + + cd ${LAUNCHPAD_DIR} + + cp ${DEBIAN_DIR}/changelog ${DEBIAN_DIR}/changelog.generic + + for LAUNCHPAD_DISTRIBUTION in ${LAUNCHPAD_DISTRIBUTIONS[*]} + do + + LOCAL_VERSION="${SOFTWARE_VERSION}~ppa${VERSION_INDEX}~${LAUNCHPAD_DISTRIBUTION}" + + cp ${DEBIAN_DIR}/changelog.generic ${DEBIAN_DIR}/changelog + + sed -i "s/SYSTEM/${LAUNCHPAD_DISTRIBUTION}/g" ${DEBIAN_DIR}/changelog + + cd ${LAUNCHPAD_DIR}/${LAUNCHPAD_PACKAGE} + if [ "$IS_KDE_CLIEN" != "1" ]; then + ./autogen.sh + fi + debuild -S -sa -kFDFE4451 + cd ${LAUNCHPAD_DIR} + + if [ ${DO_UPLOAD} ] ; then + dput -f -c ${LAUNCHPAD_DIR}/dput.conf ${LAUNCHPAD_CONF_PREFIX}-${LAUNCHPAD_DISTRIBUTION} ${LAUNCHPAD_PACKAGE}_${LOCAL_VERSION}_source.changes + fi + done + + cp ${DEBIAN_DIR}/changelog.generic ${DEBIAN_DIR}/changelog +done + +# if push is activated +#if [[ ${DO_PUSH} && ${IS_RELEASE} ]];then +# echo " Doing commit" +# git commit -m "[#1262] Released ${SOFTWARE_VERSION}" . +# +# echo " Pushing commit" +# git push origin release +#fi + +# close file descriptor +exec 3>&- + +exit 0 diff --git a/tools/build-system/launchpad/dput.conf b/tools/build-system/launchpad/dput.conf index ad0545a8ab988d416a9cbde3c7c27f20d05c7b7a..5570cc772ae5f9441a69a7006e67929de5de674e 100644 --- a/tools/build-system/launchpad/dput.conf +++ b/tools/build-system/launchpad/dput.conf @@ -19,6 +19,13 @@ incoming = ~savoirfairelinux/ubuntu/precise login = anonymous allow_unsigned_uploads = 0 +[sflphone-quantal] +fqdn = ppa.launchpad.net +method = ftp +incoming = ~savoirfairelinux/ubuntu/quantal +login = anonymous +allow_unsigned_uploads = 0 + [sflphone-nightly-natty] fqdn = ppa.launchpad.net method = ftp @@ -39,3 +46,31 @@ method = ftp incoming = ~savoirfairelinux/sflphone-nightly/ubuntu/precise login = anonymous allow_unsigned_uploads = 0 + +[sflphone-testing-precise] +fqdn = ppa.launchpad.net +method = ftp +incoming = ~savoirfairelinux/sflphone-testing/ubuntu/precise +login = anonymous +allow_unsigned_uploads = 0 + +[sflphone-testing-quantal] +fqdn = ppa.launchpad.net +method = ftp +incoming = ~savoirfairelinux/sflphone-testing/ubuntu/quantal +login = anonymous +allow_unsigned_uploads = 0 + +[sflphone-testing-oneiric] +fqdn = ppa.launchpad.net +method = ftp +incoming = ~savoirfairelinux/sflphone-testing/ubuntu/oneiric +login = anonymous +allow_unsigned_uploads = 0 + +[sflphone-nightly-quantal] +fqdn = ppa.launchpad.net +method = ftp +incoming = ~savoirfairelinux/sflphone-nightly/ubuntu/quantal +login = anonymous +allow_unsigned_uploads = 0 diff --git a/tools/build-system/launchpad/sflphone-client-kde/debian/control b/tools/build-system/launchpad/sflphone-client-kde/debian/control index 81071246bc266ff27b56e4ab5738882c97c25f02..d868f950255eb2fe8b19bbc3f9d5b6e5f50a3499 100644 --- a/tools/build-system/launchpad/sflphone-client-kde/debian/control +++ b/tools/build-system/launchpad/sflphone-client-kde/debian/control @@ -3,10 +3,10 @@ Section: kde Priority: optional Maintainer: Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> Uploaders: Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> -Build-Depends: debhelper (>= 5.0), cdbs, kdelibs5-dev, cmake, kdepimlibs5-dev, +Build-Depends: debhelper (>= 5.0), cdbs, kdelibs5-dev, cmake, kdepimlibs5-dev, libboost-dev, Homepage: http://www.sfphone.org/ Package: sflphone-client-kde Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libqt4-dbus, kdelibs5, kdepimlibs5, sflphone-common -Description:KDE client for the sflphone-daemon SIP/IAX softphone \ No newline at end of file +Description:KDE client for the sflphone-daemon SIP/IAX softphone diff --git a/tools/build-system/setenv.sh b/tools/build-system/setenv.sh index cecbc8e880dd91c5a4c045ebb79073c53e0774aa..20048139b0fb407d5ceb1b6e757d40b4a2e37c6c 100644 --- a/tools/build-system/setenv.sh +++ b/tools/build-system/setenv.sh @@ -22,5 +22,5 @@ export REFERENCE_REPOSITORY="${ROOT_DIR}/sflphone-source-repository" export WORKING_DIR="${ROOT_DIR}/sflphone-build-repository/tools/build-system" export LAUNCHPAD_DIR="${WORKING_DIR}/launchpad" -LAUNCHPAD_DISTRIBUTIONS=("natty" "oneiric" "precise") +LAUNCHPAD_DISTRIBUTIONS=("natty" "oneiric" "precise" "quantal") export LAUNCHPAD_DISTRIBUTIONS