From 431cee5d12fbf6243efa38eb8957f4e7c9d1b32e Mon Sep 17 00:00:00 2001 From: philippegorley <philippe.gorley@savoirfairelinux.com> Date: Wed, 31 Jul 2019 13:50:58 -0400 Subject: [PATCH] recorder: add preferences Adds whether or not the local video feed should be overlaid on the remote video feed. Adds a quality setting for the recorder. Change-Id: I60bd80c6441c7d516120680bebb1acdeb3824c49 --- .../cx.ring.Ring.ConfigurationManager.xml | 20 ++++++++++ bin/dbus/dbusconfigurationmanager.cpp | 24 ++++++++++++ bin/dbus/dbusconfigurationmanager.h | 4 ++ bin/jni/configurationmanager.i | 4 ++ bin/nodejs/configurationmanager.i | 4 ++ configure.ac | 2 +- src/client/configurationmanager.cpp | 39 +++++++++++++++++++ src/dring/configurationmanager_interface.h | 5 +++ src/manager.cpp | 8 +--- src/media/media_encoder.cpp | 2 + src/media/media_filter.cpp | 3 +- src/media/media_recorder.cpp | 2 + src/media/media_stream.h | 13 ++++--- src/media/video/filter_transpose.cpp | 2 +- src/media/video/video_rtp_session.cpp | 9 +++-- src/preferences.cpp | 16 +++++++- src/preferences.h | 19 +++++++++ 17 files changed, 155 insertions(+), 21 deletions(-) diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml index b991b6f974..88543d88d4 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 acecf61030..223cbdfbe2 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 459ac565dc..62abc3eb52 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 846899d497..5eccdb62f6 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 aee3d5e4a1..8665c41b64 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 536927e525..53bb952102 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 91b307d505..0ecbddaf78 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 56c0540158..6a5c335775 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 d2bc4fdf69..3da74cb1b7 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 f43bfe6d80..c7465bc2ce 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 13884ea90d..18b6f5ec33 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 f275fb3438..4da743ade1 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 0cac0eae67..4f92f885a3 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 ca96a4816a..3a2c90e9e5 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 45aa79e01e..dad69d876a 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 ec643718e9..86367c22dd 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 61851efb54..f78c81c4f7 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 -- GitLab