diff --git a/daemon/src/sip/sdp.cpp b/daemon/src/sip/sdp.cpp index 101498760e58ee879c63e92240b329874b04334b..9dc555a8fc074704771623cbd975cddf121a9127 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; @@ -424,7 +428,7 @@ string Sdp::getLineFromSession(const pjmedia_sdp_session *sess, const string &ke return ""; } -string Sdp::getActiveIncomingVideoDescription() const +string Sdp::getIncomingVideoDescription() const { stringstream ss; ss << "v=0" << std::endl; @@ -471,10 +475,10 @@ string Sdp::getActiveIncomingVideoDescription() const return ss.str(); } -std::string Sdp::getActiveOutgoingVideoCodec() const +std::string Sdp::getOutgoingVideoCodec() const { string str("a=rtpmap:"); - str += getActiveOutgoingVideoPayload(); + str += getOutgoingVideoPayload(); string vCodecLine(getLineFromSession(activeRemoteSession_, str)); char codec_buf[32]; codec_buf[0] = '\0'; @@ -482,20 +486,33 @@ 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 +std::string +Sdp::getOutgoingVideoPayload() const { string videoLine(getLineFromSession(activeRemoteSession_, "m=video")); int payload_num; @@ -539,7 +556,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 +633,24 @@ 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"); + args["parameters"] = getOutgoingVideoField(codec, "parameters"); + args["payload_type"] = getOutgoingVideoPayload(); + } + return true; + } +#endif + return false; +} diff --git a/daemon/src/sip/sdp.h b/daemon/src/sip/sdp.h index fb0f9d2eedba1f02f56733d4f550718ef5cf4a73..310c1fa5fde700acfae8dcf7cd5d2ecdf0cb3d86 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,18 @@ 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; + std::string getOutgoingVideoPayload() const; /** * The pool to allocate memory, ownership to SipCall diff --git a/daemon/src/video/video_rtp_session.cpp b/daemon/src/video/video_rtp_session.cpp index 3e3f403db775c1802bade86d03c50eefbcba3575..5d54f4f1bd4412efac99ba71d3c4902d0ccfccb9 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, diff --git a/gnome/src/config/videoconf.c b/gnome/src/config/videoconf.c index e91760a2ec6aedf080cd2fb5be96923710f04b22..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) { @@ -453,6 +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); + /* 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