diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml index b991b6f974dd4fcb08efcdfce0023373ae2b0ac6..88543d88d4c5337d23b1196c15a55a89f58a700a 100644 --- a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml +++ b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml @@ -757,6 +757,26 @@ </arg> </method> + <method name="getRecordPreview" tp:name-for-bindings="getRecordPreview"> + <arg type="b" name="res" direction="out"> + </arg> + </method> + + <method name="setRecordPreview" tp:name-for-bindings="setRecordPreview"> + <arg type="b" name="enabled" direction="in"> + </arg> + </method> + + <method name="getRecordQuality" tp:name-for-bindings="getRecordQuality"> + <arg type="i" name="res" direction="out"> + </arg> + </method> + + <method name="setRecordQuality" tp:name-for-bindings="setRecordQuality"> + <arg type="i" name="enabled" direction="in"> + </arg> + </method> + <!-- /////////////////////// --> <!-- Codecs-related methods --> diff --git a/bin/dbus/dbusconfigurationmanager.cpp b/bin/dbus/dbusconfigurationmanager.cpp index acecf61030c0a16d6a03d97164ae7178ae07f51d..223cbdfbe2407ca32ad93f94c99e28a211978f7a 100644 --- a/bin/dbus/dbusconfigurationmanager.cpp +++ b/bin/dbus/dbusconfigurationmanager.cpp @@ -431,6 +431,30 @@ DBusConfigurationManager::setIsAlwaysRecording(const bool& rec) DRing::setIsAlwaysRecording(rec); } +auto +DBusConfigurationManager::getRecordPreview() -> decltype(DRing::getRecordPreview()) +{ + return DRing::getRecordPreview(); +} + +void +DBusConfigurationManager::setRecordPreview(const bool& rec) +{ + DRing::setRecordPreview(rec); +} + +auto +DBusConfigurationManager::getRecordQuality() -> decltype(DRing::getRecordQuality()) +{ + return DRing::getRecordQuality(); +} + +void +DBusConfigurationManager::setRecordQuality(const int32_t& quality) +{ + DRing::setRecordQuality(quality); +} + void DBusConfigurationManager::setHistoryLimit(const int32_t& days) { diff --git a/bin/dbus/dbusconfigurationmanager.h b/bin/dbus/dbusconfigurationmanager.h index 459ac565dcbb58ff26d6cfd9b1e1164a50796eb5..62abc3eb5256e266257090ed40f2778a56170730 100644 --- a/bin/dbus/dbusconfigurationmanager.h +++ b/bin/dbus/dbusconfigurationmanager.h @@ -126,6 +126,10 @@ class DRING_PUBLIC DBusConfigurationManager : void setRecordPath(const std::string& recPath); bool getIsAlwaysRecording(); void setIsAlwaysRecording(const bool& rec); + bool getRecordPreview(); + void setRecordPreview(const bool& rec); + int32_t getRecordQuality(); + void setRecordQuality(const int32_t& quality); void setHistoryLimit(const int32_t& days); int32_t getHistoryLimit(); void setRingingTimeout(const int32_t& timeout); diff --git a/bin/jni/configurationmanager.i b/bin/jni/configurationmanager.i index 846899d497917dd4ae25aa628ed9e3b2d6c34e22..5eccdb62f66183c58b981649bb8127e88d5de228 100644 --- a/bin/jni/configurationmanager.i +++ b/bin/jni/configurationmanager.i @@ -148,6 +148,10 @@ std::string getRecordPath(); void setRecordPath(const std::string& recPath); bool getIsAlwaysRecording(); void setIsAlwaysRecording(bool rec); +bool getRecordPreview(); +void setRecordPreview(bool rec); +int32_t getRecordQuality(); +void setRecordQuality(int32_t rec); void setHistoryLimit(int32_t days); int32_t getHistoryLimit(); diff --git a/bin/nodejs/configurationmanager.i b/bin/nodejs/configurationmanager.i index aee3d5e4a1c24678329b6240daccee18d03d79b6..8665c41b6483eb93a55c067c09436957d254d9ef 100644 --- a/bin/nodejs/configurationmanager.i +++ b/bin/nodejs/configurationmanager.i @@ -142,6 +142,10 @@ std::string getRecordPath(); void setRecordPath(const std::string& recPath); bool getIsAlwaysRecording(); void setIsAlwaysRecording(bool rec); +bool getRecordPreview(); +void setRecordPreview(bool rec); +int32_t getRecordQuality(); +void setRecordQuality(int32_t rec); void setHistoryLimit(int32_t days); int32_t getHistoryLimit(); diff --git a/configure.ac b/configure.ac index 536927e525b7bcfe722b50031f4da1fd8724388c..53bb95210290c42eaf1d0cb700098a466c8a0b48 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl Jami - configure.ac for automake 1.9 and autoconf 2.59 dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) -AC_INIT([Jami Daemon],[7.7.0],[ring@gnu.org],[jami]) +AC_INIT([Jami Daemon],[7.8.0],[ring@gnu.org],[jami]) AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2019]]) AC_REVISION([$Revision$]) diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp index 91b307d50548bc250dad45cd8cad055e4764e6e6..0ecbddaf78229dbe8f2db67962d46b49ecb62c85 100644 --- a/src/client/configurationmanager.cpp +++ b/src/client/configurationmanager.cpp @@ -5,6 +5,7 @@ * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com> * Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -697,6 +698,44 @@ setIsAlwaysRecording(bool rec) jami::Manager::instance().setIsAlwaysRecording(rec); } +bool +getRecordPreview() +{ +#ifdef ENABLE_VIDEO + return jami::Manager::instance().videoPreferences.getRecordPreview(); +#else + return false; +#endif +} + +void +setRecordPreview(bool rec) +{ +#ifdef ENABLE_VIDEO + jami::Manager::instance().videoPreferences.setRecordPreview(rec); + jami::Manager::instance().saveConfig(); +#endif +} + +int32_t +getRecordQuality() +{ +#ifdef ENABLE_VIDEO + return jami::Manager::instance().videoPreferences.getRecordQuality(); +#else + return 0; +#endif +} + +void +setRecordQuality(int32_t quality) +{ +#ifdef ENABLE_VIDEO + jami::Manager::instance().videoPreferences.setRecordQuality(quality); + jami::Manager::instance().saveConfig(); +#endif +} + int32_t getHistoryLimit() { diff --git a/src/dring/configurationmanager_interface.h b/src/dring/configurationmanager_interface.h index 56c0540158cb2050f247028c42eec933be526614..6a5c335775c44aa31be622412d96941a6d84a7e7 100644 --- a/src/dring/configurationmanager_interface.h +++ b/src/dring/configurationmanager_interface.h @@ -7,6 +7,7 @@ * Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com> * Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com> * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -126,6 +127,10 @@ DRING_PUBLIC std::string getRecordPath(); DRING_PUBLIC void setRecordPath(const std::string& recPath); DRING_PUBLIC bool getIsAlwaysRecording(); DRING_PUBLIC void setIsAlwaysRecording(bool rec); +DRING_PUBLIC bool getRecordPreview(); +DRING_PUBLIC void setRecordPreview(bool rec); +DRING_PUBLIC int getRecordQuality(); +DRING_PUBLIC void setRecordQuality(int quality); DRING_PUBLIC void setHistoryLimit(int32_t days); DRING_PUBLIC int32_t getHistoryLimit(); diff --git a/src/manager.cpp b/src/manager.cpp index d2bc4fdf696d5ed9edb4d5450fe65baae4b97023..3da74cb1b77957ecd024c891590ca2e0c7a055d5 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -10,6 +10,7 @@ * Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com> * Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -982,10 +983,6 @@ Manager::answerCall(const std::string& call_id) addAudio(*call); - // Start recording if set in preference - if (audioPreference.getIsAlwaysRecording()) - toggleRecordingCall(call_id); - return result; } @@ -1995,9 +1992,6 @@ Manager::peerAnsweredCall(Call& call) getRingBufferPool().flushAllBuffers(); pimpl_->audiodriver_->flushUrgent(); } - - if (audioPreference.getIsAlwaysRecording()) - toggleRecordingCall(call_id); } //THREAD=VoIP Call=Outgoing diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp index f43bfe6d804237d65add2e0ee01bf52760c31b4a..c7465bc2cecf3833a4e9cf691bf97190bf28a2c1 100644 --- a/src/media/media_encoder.cpp +++ b/src/media/media_encoder.cpp @@ -94,6 +94,8 @@ MediaEncoder::setOptions(const MediaStream& opts) videoOpts_.height -= videoOpts_.height % 2; if (not videoOpts_.frameRate) videoOpts_.frameRate = 30; + if (opts.bitrate) + libav_utils::setDictValue(&options_, "max_rate", std::to_string(opts.bitrate)); } else { audioOpts_ = opts; } diff --git a/src/media/media_filter.cpp b/src/media/media_filter.cpp index 13884ea90d5f06af573b6a6d1408b7fecd6b7ffe..18b6f5ec33fc9c45cfbd0caf0f36a08f98a71df4 100644 --- a/src/media/media_filter.cpp +++ b/src/media/media_filter.cpp @@ -136,7 +136,7 @@ MediaFilter::getOutputParams() const output.timeBase = av_buffersink_get_time_base(output_); output.width = av_buffersink_get_w(output_); output.height = av_buffersink_get_h(output_); - output.aspectRatio = av_buffersink_get_sample_aspect_ratio(output_); + output.bitrate = 0; output.frameRate = av_buffersink_get_frame_rate(output_); break; case AVMEDIA_TYPE_AUDIO: @@ -275,7 +275,6 @@ MediaFilter::initInputFilter(AVFilterInOut* in, MediaStream msp) if (mediaType == AVMEDIA_TYPE_VIDEO) { params->width = msp.width; params->height = msp.height; - params->sample_aspect_ratio = msp.aspectRatio; params->frame_rate = msp.frameRate; buffersrc = avfilter_get_by_name("buffer"); } else { diff --git a/src/media/media_recorder.cpp b/src/media/media_recorder.cpp index f275fb343839869fd2a8a1832c8de6f0b7199da1..4da743ade1ea0182e0c1b68cb8a799e9564cc655 100644 --- a/src/media/media_recorder.cpp +++ b/src/media/media_recorder.cpp @@ -22,6 +22,7 @@ #include "client/ring_signal.h" #include "fileutils.h" #include "logger.h" +#include "manager.h" #include "media_io_handle.h" #include "media_recorder.h" #include "system_codec_container.h" @@ -352,6 +353,7 @@ MediaRecorder::setupVideoOutput() if (ret >= 0) { encoderStream = videoFilter_->getOutputParams(); + encoderStream.bitrate = Manager::instance().videoPreferences.getRecordQuality(); JAMI_DBG() << "Recorder output: " << encoderStream; } else { JAMI_ERR() << "Failed to initialize video filter"; diff --git a/src/media/media_stream.h b/src/media/media_stream.h index 0cac0eae675ee5b85762a59f909cdd4c675f941f..4f92f885a3daf85e05516ad642e6a440f0c8c070 100644 --- a/src/media/media_stream.h +++ b/src/media/media_stream.h @@ -37,7 +37,7 @@ struct MediaStream { int64_t firstTimestamp {0}; int width {0}; int height {0}; - rational<int> aspectRatio; + int bitrate; rational<int> frameRate; int sampleRate {0}; int nbChannels {0}; @@ -47,14 +47,14 @@ struct MediaStream { {} MediaStream(const std::string& streamName, int fmt, rational<int> tb, int w, int h, - rational<int> sar, rational<int> fr) + int br, rational<int> fr) : name(streamName) , format(fmt) , isVideo(true) , timeBase(tb) , width(w) , height(h) - , aspectRatio(sar) + , bitrate(br) , frameRate(fr) {} @@ -99,7 +99,7 @@ struct MediaStream { isVideo = true; width = c->width; height = c->height; - aspectRatio = c->sample_aspect_ratio; + bitrate = c->bit_rate; frameRate = c->framerate; break; case AVMEDIA_TYPE_AUDIO: @@ -131,12 +131,11 @@ struct MediaStream { void update(AVFrame* f) { - // update all info possible (AVFrame has no fps data) + // update all info possible (AVFrame has no fps or bitrate data) format = f->format; if (isVideo) { width = f->width; height = f->height; - aspectRatio = f->sample_aspect_ratio; } else { sampleRate = f->sample_rate; nbChannels = f->channels; @@ -154,6 +153,8 @@ inline std::ostream& operator<<(std::ostream& os, const MediaStream& ms) << av_get_pix_fmt_name(static_cast<AVPixelFormat>(ms.format)) << " video, " << ms.width << "x" << ms.height << ", " << ms.frameRate << " fps (" << ms.timeBase << ")"; + if (ms.bitrate > 0) + os << ", " << ms.bitrate << " kb/s"; } else { os << (ms.name.empty() ? "(null)" : ms.name) << ": " << av_get_sample_fmt_name(static_cast<AVSampleFormat>(ms.format)) << " audio, " diff --git a/src/media/video/filter_transpose.cpp b/src/media/video/filter_transpose.cpp index ca96a4816a26f41f5103d8c0f3c50cc1b5e287d6..3a2c90e9e5c1b2124889445ee2850b11240ce4f0 100644 --- a/src/media/video/filter_transpose.cpp +++ b/src/media/video/filter_transpose.cpp @@ -64,7 +64,7 @@ getTransposeFilter(int rotation, std::string inputName, int width, int height, i const auto one = rational<int>(1); std::vector<MediaStream> msv; - msv.emplace_back(inputName, format, one, width, height, one, one); + msv.emplace_back(inputName, format, one, width, height, 0, one); std::unique_ptr<MediaFilter> filter(new MediaFilter); auto ret = filter->initialize(ss.str(), msv); diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index 45aa79e01e69f66291c28ed38eb57688b5889445..dad69d876ae461f00ec837a4843f88457631c92a 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -3,6 +3,7 @@ * * Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com> * Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -505,9 +506,11 @@ VideoRtpSession::initRecorder(std::shared_ptr<MediaRecorder>& rec) receiveThread_->attach(ob); } } - if (auto input = std::static_pointer_cast<VideoInput>(videoLocal_)) { - if (auto ob = rec->addStream(input->getInfo())) { - input->attach(ob); + if (Manager::instance().videoPreferences.getRecordPreview()) { + if (auto input = std::static_pointer_cast<VideoInput>(videoLocal_)) { + if (auto ob = rec->addStream(input->getInfo())) { + input->attach(ob); + } } } } diff --git a/src/preferences.cpp b/src/preferences.cpp index ec643718e9b7d36023bddde8f2bdb3e730a2fc74..86367c22dd3cc9b6a41708e67da9d58f185e21bf 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2004-2019 Savoir-faire Linux Inc. * * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -139,6 +140,8 @@ static constexpr const char* TOGGLE_PICKUP_HANGUP_SHORT_KEY {"togglePickupHangup constexpr const char * const VideoPreferences::CONFIG_LABEL; static constexpr const char* DECODING_ACCELERATED_KEY {"decodingAccelerated"}; static constexpr const char* ENCODING_ACCELERATED_KEY {"encodingAccelerated"}; +static constexpr const char* RECORD_PREVIEW_KEY {"recordPreview"}; +static constexpr const char* RECORD_QUALITY_KEY {"recordQuality"}; #endif static constexpr int PULSE_LENGTH_DEFAULT {250}; /** Default DTMF length */ @@ -564,12 +567,16 @@ void ShortcutPreferences::unserialize(const YAML::Node &in) VideoPreferences::VideoPreferences() : decodingAccelerated_(true) , encodingAccelerated_(false) + , recordPreview_(true) + , recordQuality_(0) { } void VideoPreferences::serialize(YAML::Emitter &out) const { out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap; + out << YAML::Key << RECORD_PREVIEW_KEY << YAML::Value << recordPreview_; + out << YAML::Key << RECORD_QUALITY_KEY << YAML::Value << recordQuality_; #ifdef RING_ACCEL out << YAML::Key << DECODING_ACCELERATED_KEY << YAML::Value << decodingAccelerated_; out << YAML::Key << ENCODING_ACCELERATED_KEY << YAML::Value << encodingAccelerated_; @@ -580,9 +587,16 @@ void VideoPreferences::serialize(YAML::Emitter &out) const void VideoPreferences::unserialize(const YAML::Node &in) { + // values may or may not be present const auto &node = in[CONFIG_LABEL]; + try { + parseValue(node, RECORD_PREVIEW_KEY, recordPreview_); + parseValue(node, RECORD_QUALITY_KEY, recordQuality_); + } catch (...) { + recordPreview_ = true; + recordQuality_ = 0; + } #ifdef RING_ACCEL - // value may or may not be present try { parseValue(node, DECODING_ACCELERATED_KEY, decodingAccelerated_); parseValue(node, ENCODING_ACCELERATED_KEY, encodingAccelerated_); diff --git a/src/preferences.h b/src/preferences.h index 61851efb54ee009aa32b62c2a1396c4843457b75..f78c81c4f7a948599f2e60bcfd49b219b080ca2a 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -2,6 +2,7 @@ * Copyright (C) 2004-2019 Savoir-faire Linux Inc. * * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -475,9 +476,27 @@ class VideoPreferences : public Serializable { emitSignal<DRing::ConfigurationSignal::HardwareEncodingChanged>(encodingAccelerated_); } + bool getRecordPreview() const { + return recordPreview_; + } + + void setRecordPreview(bool rec) { + recordPreview_ = rec; + } + + int getRecordQuality() const { + return recordQuality_; + } + + void setRecordQuality(int rec) { + recordQuality_ = rec; + } + private: bool decodingAccelerated_; bool encodingAccelerated_; + bool recordPreview_; + int recordQuality_; constexpr static const char* const CONFIG_LABEL = "video"; }; #endif // ENABLE_VIDEO