Commit 3939750f authored by Éloi Bail's avatar Éloi Bail Committed by Stepan Salenikovich

daemon: change bitrate in live

If user changed codec parameters such as bitrate using dbus API, audio and
video codec will be automatically restart with up-to-date parameters.

Audio and video ports previously negotiated on the previous media session will
stay the same. In order to avoid dropped framed, RTP sequence number from
previous session will be reused. Thus new session will use continuous sequence
number.

Refs #77483
Change-Id: Idce0f8b3a0537f0db6def054cfdb8765440d2cd7
parent b44f84d2
......@@ -325,6 +325,8 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> {
return iceTransport_;
}
virtual void restartMediaSender() = 0;
protected:
/**
* Constructor of a call
......
......@@ -408,6 +408,14 @@ setCodecDetails(const std::string& accountID,
if (codec->systemCodecInfo.mediaType & ring::MEDIA_VIDEO) {
if (auto foundCodec = std::static_pointer_cast<ring::AccountVideoCodecInfo>(codec)) {
foundCodec->setCodecSpecifications(details);
RING_WARN("parameters for %s changed ",
foundCodec->systemCodecInfo.name.c_str());
if (foundCodec->isRunning) {
RING_WARN("%s running. Need to restart encoding",
foundCodec->systemCodecInfo.name.c_str());
auto call = ring::Manager::instance().getCurrentCall();
call->restartMediaSender();
}
return true;
}
}
......
......@@ -134,6 +134,9 @@ class IAXCall : public Call
//TODO: implement mute for IAX
void muteMedia(const std::string& mediaType, bool isMuted) {}
//TODO: implement restartMedia for IAX
void restartMediaSender() {}
void peerHungup();
void carryingDTMFdigits(char code);
......
......@@ -56,10 +56,12 @@ class AudioSender {
AudioSender(const std::string& id,
const std::string& dest,
const MediaDescription& args,
SocketPair& socketPair);
SocketPair& socketPair,
const uint16_t seqVal);
~AudioSender();
void setMuted(bool isMuted);
uint16_t getLastSeqValue();
private:
NON_COPYABLE(AudioSender);
......@@ -75,6 +77,7 @@ class AudioSender {
AudioBuffer micData_;
AudioBuffer resampledData_;
const uint16_t seqVal_;
using seconds = std::chrono::duration<double, std::ratio<1>>;
const seconds secondsPerPacket_ {0.02}; // 20 ms
......@@ -87,10 +90,12 @@ class AudioSender {
AudioSender::AudioSender(const std::string& id,
const std::string& dest,
const MediaDescription& args,
SocketPair& socketPair) :
SocketPair& socketPair,
const uint16_t seqVal) :
id_(id),
dest_(dest),
args_(args),
seqVal_(seqVal),
loop_([&] { return setup(socketPair); },
std::bind(&AudioSender::process, this),
std::bind(&AudioSender::cleanup, this))
......@@ -113,6 +118,7 @@ AudioSender::setup(SocketPair& socketPair)
/* Encoder setup */
RING_WARN("audioEncoder_->openOutput %s", dest_.c_str());
audioEncoder_->openOutput(dest_.c_str(), args_);
audioEncoder_->setInitSeqVal(seqVal_);
audioEncoder_->setIOContext(muxContext_);
audioEncoder_->startIO();
} catch (const MediaEncoderException &e) {
......@@ -186,6 +192,12 @@ AudioSender::setMuted(bool isMuted)
audioEncoder_->setMuted(isMuted);
}
uint16_t
AudioSender::getLastSeqValue()
{
return audioEncoder_->getLastSeqValue();
}
class AudioReceiveThread
{
......@@ -375,7 +387,7 @@ AudioRtpSession::startSender()
try {
sender_.reset(new AudioSender(callID_, getRemoteRtpUri(), send_,
*socketPair_));
*socketPair_, initSeqVal_));
} catch (const MediaEncoderException &e) {
RING_ERR("%s", e.what());
send_.enabled = false;
......@@ -479,4 +491,20 @@ AudioRtpSession::setMuted(bool isMuted)
sender_->setMuted(isMuted);
}
void
AudioRtpSession::setSenderInitSeqVal(const uint16_t seqVal)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
initSeqVal_ = seqVal;
}
uint16_t
AudioRtpSession::getSenderLastSeqValue()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (sender_)
return sender_->getLastSeqValue();
return 0;
}
} // namespace ring
......@@ -56,6 +56,8 @@ class AudioRtpSession : public RtpSession {
std::unique_ptr<IceSocket> rtcp_sock);
void stop();
void setMuted(bool isMuted);
void setSenderInitSeqVal(const uint16_t seqVal);
uint16_t getSenderLastSeqValue();
private:
void startSender();
......@@ -64,6 +66,7 @@ class AudioRtpSession : public RtpSession {
std::unique_ptr<AudioSender> sender_;
std::unique_ptr<AudioReceiveThread> receiveThread_;
std::shared_ptr<RingBuffer> ringbuffer_;
uint16_t initSeqVal_;
};
} // namespace ring
......
......@@ -145,6 +145,7 @@ AccountCodecInfo::AccountCodecInfo(const SystemCodecInfo& sysCodecInfo)
: systemCodecInfo(sysCodecInfo)
, order(0)
, isActive(true)
, isRunning(false)
, payloadType(sysCodecInfo.payloadType)
, bitrate(sysCodecInfo.bitrate)
{}
......
......@@ -147,6 +147,7 @@ struct AccountCodecInfo
const SystemCodecInfo& systemCodecInfo;
unsigned order; /*used to define prefered codec list order in UI*/
bool isActive;
bool isRunning; /*is this codec processing data or not*/
/* account custom values */
unsigned payloadType;
unsigned bitrate;
......
......@@ -54,8 +54,10 @@ MediaEncoder::MediaEncoder()
MediaEncoder::~MediaEncoder()
{
if (outputCtx_ and outputCtx_->priv_data)
if (outputCtx_ and outputCtx_->priv_data) {
av_write_trailer(outputCtx_);
*isCodecRunning = false;
}
if (encoderCtx_)
avcodec_close(encoderCtx_);
......@@ -99,6 +101,27 @@ void MediaEncoder::setOptions(const MediaDescription& args)
if (not args.parameters.empty())
av_dict_set(&options_, "parameters", args.parameters.c_str(), 0);
isCodecRunning = &(args.codec->isRunning);
}
void
MediaEncoder::setInitSeqVal(uint16_t seqVal)
{
//only set not default value (!=0)
if (seqVal != 0)
av_dict_set(&options_, "seq", ring::to_string(seqVal).c_str(), 0);
}
uint16_t
MediaEncoder::getLastSeqValue()
{
int64_t retVal;
auto ret = av_opt_get_int(outputCtx_->priv_data, "seq", AV_OPT_SEARCH_CHILDREN, &retVal);
if (ret == 0)
return (uint16_t) retVal;
else
return 0;
}
void
......@@ -215,6 +238,7 @@ MediaEncoder::startIO()
}
av_dump_format(outputCtx_, 0, outputCtx_->filename, 1);
*isCodecRunning = true;
}
static void
......
......@@ -91,6 +91,9 @@ public:
int getHeight() const { return device_.height; }
void setMuted(bool isMuted);
void setInitSeqVal(uint16_t seqVal);
uint16_t getLastSeqValue();
private:
NON_COPYABLE(MediaEncoder);
......@@ -119,6 +122,7 @@ private:
int encoderBufferSize_ = 0;
#endif
bool is_muted = false;
bool* isCodecRunning = nullptr;
protected:
AVDictionary *options_ = nullptr;
......
......@@ -57,6 +57,9 @@ public:
receive_ = receive;
}
virtual void setSenderInitSeqVal(uint16_t seqVal) = 0;
virtual uint16_t getSenderLastSeqValue() = 0;
bool isSending() { return send_.enabled; }
bool isReceiving() { return receive_.enabled; }
......
......@@ -91,7 +91,8 @@ void VideoRtpSession::startSender()
try {
sender_.reset(
new VideoSender(getRemoteRtpUri(), localVideoParams_, send_, *socketPair_)
new VideoSender(getRemoteRtpUri(), localVideoParams_,
send_, *socketPair_, initSeqVal_)
);
} catch (const MediaEncoderException &e) {
RING_ERR("%s", e.what());
......@@ -100,6 +101,11 @@ void VideoRtpSession::startSender()
}
}
void VideoRtpSession::restartSender()
{
startSender();
}
void VideoRtpSession::startReceiver()
{
if (receive_.enabled and not receive_.holding) {
......@@ -281,4 +287,20 @@ void VideoRtpSession::exitConference()
conference_ = nullptr;
}
void
VideoRtpSession::setSenderInitSeqVal(const uint16_t seqVal)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
initSeqVal_ = seqVal;
}
uint16_t
VideoRtpSession::getSenderLastSeqValue()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (sender_)
return sender_->getLastSeqValue();
return 0;
}
}} // namespace ring::video
......@@ -70,6 +70,10 @@ public:
input_ = input;
}
void restartSender();
void setSenderInitSeqVal(uint16_t seqVal);
uint16_t getSenderLastSeqValue();
private:
void setupConferenceVideoPipeline(Conference *conference);
void startSender();
......@@ -83,6 +87,7 @@ private:
Conference* conference_ {nullptr};
std::shared_ptr<VideoMixer> videoMixer_;
std::shared_ptr<VideoFrameActiveWriter> videoLocal_;
uint16_t initSeqVal_ = 0;
};
}} // namespace ring::video
......
......@@ -44,18 +44,26 @@ namespace ring { namespace video {
using std::string;
VideoSender::VideoSender(const std::string& dest, const DeviceParams& dev,
const MediaDescription& args, SocketPair& socketPair)
const MediaDescription& args, SocketPair& socketPair,
const uint16_t seqVal)
: muxContext_(socketPair.createIOContext())
, videoEncoder_(new MediaEncoder)
{
videoEncoder_->setDeviceOptions(dev);
videoEncoder_->openOutput(dest.c_str(), args);
videoEncoder_->setInitSeqVal(seqVal);
videoEncoder_->setIOContext(muxContext_);
videoEncoder_->startIO();
videoEncoder_->print_sdp(sdp_);
}
VideoSender::~VideoSender()
{
videoEncoder_->flush();
}
void VideoSender::encodeAndSendVideo(VideoFrame& input_frame)
{
bool is_keyframe = forceKeyFrame_ > 0;
......@@ -83,4 +91,10 @@ void VideoSender::setMuted(bool isMuted)
videoEncoder_->setMuted(isMuted);
}
uint16_t
VideoSender::getLastSeqValue()
{
return videoEncoder_->getLastSeqValue();
}
}} // namespace ring::video
......@@ -54,7 +54,10 @@ public:
VideoSender(const std::string& dest,
const DeviceParams& dev,
const MediaDescription& args,
SocketPair& socketPair);
SocketPair& socketPair,
const uint16_t seqVal);
~VideoSender();
std::string getSDP() const { return sdp_; }
void forceKeyFrame();
......@@ -64,6 +67,7 @@ public:
std::shared_ptr<VideoFrame> &);
void setMuted(bool isMuted);
uint16_t getLastSeqValue();
private:
NON_COPYABLE(VideoSender);
......
......@@ -795,7 +795,7 @@ SIPCall::startIce()
}
void
SIPCall::startAllMedia()
SIPCall::startAllMedia(const uint16_t seqVideoInitVal, const uint16_t seqAudioInitVal)
{
if (isSecure() && not transport_->isSecure()) {
RING_ERR("Can't perform secure call over insecure SIP transport");
......@@ -846,8 +846,13 @@ SIPCall::startAllMedia()
#ifdef RING_VIDEO
if (local.type == MEDIA_VIDEO) {
videortp_.switchInput(videoInput_);
rtp->setSenderInitSeqVal(seqVideoInitVal);
}
#endif
if (local.type == MEDIA_AUDIO){
rtp->setSenderInitSeqVal(seqAudioInitVal);
}
rtp->updateMedia(remote, local);
if (isIceRunning()) {
rtp->start(newIceSocket(ice_comp_id + 0),
......@@ -875,6 +880,23 @@ SIPCall::startAllMedia()
}
}
void
SIPCall::restartMediaSender()
{
uint16_t lastSeqVideoVal, lastSeqAudioVal = 0;
#ifdef RING_VIDEO
lastSeqVideoVal = videortp_.getSenderLastSeqValue() + 1;
lastSeqAudioVal = avformatrtp_->getSenderLastSeqValue() + 1;
RING_WARN("restarting video and audio streams");
#else
lastSeqAudioVal = avformatrtp_->getSenderLastSeqValue() + 1;
RING_WARN("restarting audio streams");
#endif
stopAllMedia();
RING_ERR("lastSeqVideoVal=%u, lastSeqAudioVal=%u", lastSeqVideoVal,lastSeqAudioVal);
startAllMedia(lastSeqVideoVal, lastSeqAudioVal);
}
void
SIPCall::stopAllMedia()
{
......
......@@ -199,7 +199,8 @@ class SIPCall : public Call
bool startIce();
void startAllMedia();
void startAllMedia(const uint16_t seqVideoInitVal = 0,
const uint16_t seqAudioInitVal = 0);
void onMediaUpdate();
......@@ -209,6 +210,8 @@ class SIPCall : public Call
void muteMedia(const std::string& mediaType, bool isMuted);
void restartMediaSender();
virtual std::map<std::string, std::string> getDetails() const;
private:
......
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