Commit 0dc32710 authored by Gasuleg's avatar Gasuleg Committed by Guillaume Roguez

daemon: add SmartInfo

This feature provides relevant advanced information during a call.
A user starts it with a refresh time and listens on a callback signal
to get the updated information. This information is presented in a form
of a map containing Call ID, codecs, framerate and resolution.

The public API has:
- startSmartInfo(<timeMS>)
- stopSmartInfo()
- CallSignal::SmartInfo(map) -- callback signal

Change-Id: Iaafc12b5b53aee8ad008b93536f72a4152c4ee02
Reviewed-by: Guillaume Roguez's avatarGuillaume Roguez <guillaume.roguez@savoirfairelinux.com>
parent 082d9dd1
......@@ -35,9 +35,16 @@
</tp:docstring>
</arg>
<arg type="b" name="refuseSucceeded" direction="out"/>
</method>
<signal name="SmartInfo" tp:name-for-bindings="SmartInfo">
<tp:docstring>
Once enabled using the startSmartInfo method, this signal is emitted every refreshTimeMS
</tp:docstring>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="MapStringString"/>
<arg type="a{ss}" name="info" direction="out" />
</signal>
<method name="accept" tp:name-for-bindings="accept">
<tp:docstring>
Answer an incoming call. Automatically puts the current call on HOLD.
......@@ -344,6 +351,23 @@
</arg>
</method>
<method name="startSmartInfo" tp:name-for-bindings="startSmartInfo">
<tp:docstring>
Start sending the signal smartInfo
</tp:docstring>
<arg type="u" name="refreshTimeMs" direction="in">
<tp:docstring>
Set the sending time (in milliseconds) of the signal.
</tp:docstring>
</arg>
</method>
<method name="stopSmartInfo" tp:name-for-bindings="stopSmartInfo">
<tp:docstring>
Stop sending the signal smartInfo
</tp:docstring>
</method>
<method name="getIsRecording" tp:name-for-bindings="getIsRecording">
<tp:docstring>
Tells whether or not a call is being recorded.
......
......@@ -283,3 +283,15 @@ DBusCallManager::sendTextMessage(const std::string& callID, const std::map<std::
{
DRing::sendTextMessage(callID, messages, "Me", isMixed);
}
void
DBusCallManager::startSmartInfo(const uint32_t& refreshTimeMs)
{
DRing::startSmartInfo(refreshTimeMs);
}
void
DBusCallManager::stopSmartInfo()
{
DRing::stopSmartInfo();
}
......@@ -97,6 +97,8 @@ class DBusCallManager :
void requestGoClear(const std::string& callID);
void acceptEnrollment(const std::string& callID, const bool& accepted);
void sendTextMessage(const std::string& callID, const std::map<std::string, std::string>& messages, const bool& isMixed);
void startSmartInfo(const uint32_t& refreshTimeMs);
void stopSmartInfo();
};
#endif // __RING_CALLMANAGER_H__
......@@ -166,7 +166,8 @@ DBusClient::initLibrary(int flags)
exportable_callback<CallSignal::RtcpReportReceived>(bind(&DBusCallManager::onRtcpReportReceived, callM, _1, _2)),
exportable_callback<CallSignal::PeerHold>(bind(&DBusCallManager::peerHold, callM, _1, _2)),
exportable_callback<CallSignal::AudioMuted>(bind(&DBusCallManager::audioMuted, callM, _1, _2)),
exportable_callback<CallSignal::VideoMuted>(bind(&DBusCallManager::videoMuted, callM, _1, _2))
exportable_callback<CallSignal::VideoMuted>(bind(&DBusCallManager::videoMuted, callM, _1, _2)),
exportable_callback<CallSignal::SmartInfo>(bind(&DBusCallManager::SmartInfo, callM, _1))
};
// Configuration event handlers
......
......@@ -126,7 +126,9 @@ libring_la_SOURCES = \
string_utils.cpp \
rw_mutex.h \
ring_api.cpp \
rational.h
rational.h \
smartools.cpp \
smartools.h
if HAVE_WIN32
libring_la_SOURCES += \
......
......@@ -33,6 +33,8 @@
#include "logger.h"
#include "manager.h"
#include "smartools.h"
namespace DRing {
void
......@@ -142,6 +144,18 @@ removeConference(const std::string& conference_id)
ring::Manager::instance().removeConference(conference_id);
}
void
startSmartInfo(uint32_t refreshTimeMs)
{
ring::Smartools::getInstance().start(std::chrono::milliseconds(refreshTimeMs));
}
void
stopSmartInfo()
{
ring::Smartools::getInstance().stop();
}
bool
addParticipant(const std::string& callID, const std::string& confID)
{
......
......@@ -53,6 +53,7 @@ getSignalHandlers()
exported_callback<DRing::CallSignal::PeerHold>(),
exported_callback<DRing::CallSignal::VideoMuted>(),
exported_callback<DRing::CallSignal::AudioMuted>(),
exported_callback<DRing::CallSignal::SmartInfo>(),
/* Configuration */
exported_callback<DRing::ConfigurationSignal::VolumeChanged>(),
......
......@@ -67,6 +67,10 @@ std::vector<std::string> getDisplayNames(const std::string& confID);
std::string getConferenceId(const std::string& callID);
std::map<std::string, std::string> getConferenceDetails(const std::string& callID);
/* Statistic related methods */
void startSmartInfo(uint32_t refreshTimeMs);
void stopSmartInfo();
/* File Playback methods */
bool startRecordedFilePlayback(const std::string& filepath);
void stopRecordedFilePlayback(const std::string& filepath);
......@@ -200,8 +204,12 @@ struct CallSignal {
constexpr static const char* name = "AudioMuted";
using cb_type = void(const std::string&, bool);
};
struct SmartInfo {
constexpr static const char* name = "SmartInfo";
using cb_type = void(const std::map<std::string, std::string>&);
};
};
} // namespace DRing
}; // namespace DRing
#endif // DRING_CALLMANAGERI_H
......@@ -61,7 +61,6 @@ class YamlEmitter;
namespace video {
class SinkClient;
}
class PluginManager;
class AudioFile;
class DTMF;
......@@ -769,6 +768,12 @@ class Manager {
*/
std::vector<std::string> loadAccountOrder() const;
/**
* Get the Call referred by callID. If the Call does not exist, return
* empty std::shared_ptr<Call> instance
*/
std::shared_ptr<Call> getCallFromCallID(const std::string &callID) const;
private:
std::atomic_bool autoAnswer_ {false};
......@@ -779,10 +784,6 @@ class Manager {
// Set the ringtone or recorded call to be played
void updateAudioFile(const std::string &file, int sampleRate);
/**
* Get the Call referred to by callID. If the Call does not exist, return NULL
*/
std::shared_ptr<Call> getCallFromCallID(const std::string &callID) const;
/**
* Process remaining participant given a conference and the current call id.
......
......@@ -37,6 +37,7 @@
#include "audio/ringbufferpool.h"
#include "audio/resampler.h"
#include "manager.h"
#include "smartools.h"
#include <sstream>
namespace ring {
......@@ -166,6 +167,7 @@ AudioSender::process()
resampledData_.setFormat(accountAudioCodec->audioformat);
resampledData_.resize(samplesToGet);
resampler_->resample(micData_, resampledData_);
Smartools::getInstance().setLocalAudioCodec(audioEncoder_->getEncoderName());
if (audioEncoder_->encode_audio(resampledData_) < 0)
RING_ERR("encoding failed");
} else {
......@@ -281,6 +283,8 @@ AudioReceiveThread::process()
case MediaDecoder::Status::FrameFinished:
audioDecoder_->writeToRingBuffer(decodedFrame, *ringbuffer_,
mainBuffFormat);
// Refresh the remote audio codec in the callback SmartInfo
Smartools::getInstance().setRemoteAudioCodec(audioDecoder_->getDecoderName());
return;
case MediaDecoder::Status::DecodeError:
......
......@@ -416,6 +416,9 @@ int MediaDecoder::getWidth() const
int MediaDecoder::getHeight() const
{ return decoderCtx_->height; }
std::string MediaDecoder::getDecoderName() const
{ return decoderCtx_->codec->name; }
rational<double>
MediaDecoder::getFps() const
{
......
......@@ -81,6 +81,8 @@ class MediaDecoder {
int getWidth() const;
int getHeight() const;
std::string getDecoderName() const;
rational<double> getFps() const;
int getPixelFormat() const;
......
......@@ -116,6 +116,12 @@ MediaEncoder::getLastSeqValue()
return 0;
}
std::string
MediaEncoder::getEncoderName() const
{
return encoderCtx_->codec->name;
}
void
MediaEncoder::openOutput(const char *filename,
const ring::MediaDescription& args)
......
......@@ -84,6 +84,7 @@ public:
void setMuted(bool isMuted);
void setInitSeqVal(uint16_t seqVal);
uint16_t getLastSeqValue();
std::string getEncoderName() const;
bool useCodec(const AccountCodecInfo* codec) const noexcept;
......
......@@ -37,6 +37,7 @@
#include "dring/videomanager_interface.h"
#include "libav_utils.h"
#include "video_scaler.h"
#include "smartools.h"
#ifndef _WIN32
#include <sys/mman.h>
......@@ -321,13 +322,18 @@ SinkClient::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/,
const std::chrono::duration<double> seconds = currentTime - lastFrameDebug_;
++frameCount_;
if (seconds.count() > 1) {
RING_DBG("%s: FPS %f", id_.c_str(), frameCount_ / seconds.count());
std::ostringstream fps;
fps << frameCount_ / seconds.count();
// Send the framerate in smartInfo
Smartools::getInstance().setFrameRate(id_, fps.str());
frameCount_ = 0;
lastFrameDebug_ = currentTime;
}
#endif
#if HAVE_SHM
// Send the resolution in smartInfo
Smartools::getInstance().setResolution(id_, f.width(), f.height());
shm_->renderFrame(f);
#endif
......
......@@ -33,6 +33,8 @@
#include <vector>
#include <memory>
#define DEBUG_FPS
namespace ring { namespace video {
#if HAVE_SHM
......
......@@ -27,6 +27,7 @@
#include "client/videomanager.h"
#include "sinkclient.h"
#include "logger.h"
#include "smartools.h"
#include <unistd.h>
#include <map>
......@@ -119,6 +120,9 @@ bool VideoReceiveThread::setup()
if (!conf)
exitConference();
// Send remote video codec in SmartInfo
Smartools::getInstance().setRemoteVideoCodec(videoDecoder_->getDecoderName(), id_);
return true;
}
......
......@@ -26,6 +26,7 @@
#include "client/videomanager.h"
#include "logger.h"
#include "manager.h"
#include "smartools.h"
#include <map>
#include <unistd.h>
......@@ -67,6 +68,9 @@ VideoSender::encodeAndSendVideo(VideoFrame& input_frame)
if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0)
RING_ERR("encoding failed");
// Send local video codec in SmartInfo
Smartools::getInstance().setLocalVideoCodec(videoEncoder_->getEncoderName());
}
void
......
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
*
* Author: Olivier Grégoire <olivier.gregoire@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
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "smartools.h"
#include "media/media_decoder.h"
#include "media/video/video_input.h"
#include "media/video/video_device.h"
#include "dring/callmanager_interface.h"
#include "client/ring_signal.h"
#include "string_utils.h"
namespace ring {
Smartools& Smartools::getInstance()
{
// Meyers-Singleton
static Smartools instance_;
return instance_;
}
// Launch process() in new thread
Smartools::Smartools()
: loop_([this] { return true; }, [this] { process(); }, [] {})
{}
void
Smartools::sendInfo()
{
std::lock_guard<std::mutex> lk(mutexInfo_);
emitSignal<DRing::CallSignal::SmartInfo>(information_);
information_.clear();
}
void
Smartools::process()
{
// Send the signal SmartInfo
Smartools::sendInfo();
std::this_thread::sleep_for(refreshTimeMs_);
}
void
Smartools::start(std::chrono::milliseconds refreshTimeMs)
{
RING_DBG("Start SmartInfo");
refreshTimeMs_ = refreshTimeMs;
loop_.stop();
loop_.start();
}
void
Smartools::stop()
{
std::lock_guard<std::mutex> lk(mutexInfo_);
RING_DBG("Stop SmartInfo");
loop_.stop();
information_.clear();
}
//Set all the information in the map
void
Smartools::setFrameRate(const std::string& id, const std::string& fps)
{
std::lock_guard<std::mutex> lk(mutexInfo_);
if(id == "local"){
information_["local FPS"]= fps;
} else {
information_["remote FPS"]= fps;
}
}
void
Smartools::setResolution(const std::string& id, int width, int height)
{
std::lock_guard<std::mutex> lk(mutexInfo_);
if(id == "local"){
information_["local width"] = to_string(width);
information_["local height"] = to_string(height);
} else {
information_["remote width"] = to_string(width);
information_["remote height"] = to_string(height);
}
}
void
Smartools::setRemoteAudioCodec(const std::string& remoteAudioCodec)
{
std::lock_guard<std::mutex> lk(mutexInfo_);
information_["remote audio codec"]= remoteAudioCodec;
}
void
Smartools::setLocalAudioCodec(const std::string& localAudioCodec)
{
std::lock_guard<std::mutex> lk(mutexInfo_);
information_["local audio codec"]= localAudioCodec;
}
void
Smartools::setLocalVideoCodec(const std::string& localVideoCodec)
{
std::lock_guard<std::mutex> lk(mutexInfo_);
information_["local video codec"]= localVideoCodec;
}
void
Smartools::setRemoteVideoCodec(const std::string& remoteVideoCodec, const std::string& callID)
{
std::lock_guard<std::mutex> lk(mutexInfo_);
information_["remote video codec"]= remoteVideoCodec;
auto confID = Manager::instance().getCallFromCallID(callID)->getConfId();
if (confID != ""){
information_["type"]= "conference";
information_["callID"]= confID;
} else {
information_["type"]= "no conference";
information_["callID"]= callID;
}
}
} // end namespace ring
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
*
* Author: Olivier Grégoire <olivier.gregoire@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
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "threadloop.h"
#include "manager.h"
#include <string>
namespace ring {
class Smartools
{
public:
static Smartools& getInstance();
void start(std::chrono::milliseconds refreshTimeMs);
void stop();
void setFrameRate(const std::string& id, const std::string& fps);
void setResolution(const std::string& id, int width, int height);
void setLocalVideoCodec(const std::string& localVideoCodec);
void setRemoteVideoCodec(const std::string& remoteVideoCodec, const std::string& callID);
void setRemoteAudioCodec(const std::string& remoteAudioCodec);
void setLocalAudioCodec(const std::string& remoteAudioCodec);
void sendInfo();
private:
Smartools();
void process();
std::map<std::string, std::string> information_;
std::mutex mutexInfo_; // Protect information_ from multithreading
std::chrono::milliseconds refreshTimeMs_;
ThreadLoop loop_; // Has to be last member
};
} //ring namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment