From 998791a36d7cb974b356ad9ca8cd8b1977ee972a Mon Sep 17 00:00:00 2001
From: Philip-Dylan Gleonec <philip-dylan.gleonec@savoirfairelinux.com>
Date: Fri, 15 Jan 2021 16:01:16 +0100
Subject: [PATCH] media_encoder: add setPacketLoss method

Add a setPacketLoss method to enable setting a new packet loss
estimation in the codec.
This method follows the model of setBitrate and requires the
implementation of getCurrentAudioAVCtx and isDynPacketLossSupported,
which are also included in this patch.

Issue: #5157
Change-Id: I62f5246df1df0dc0867649299c6bbf6c12db43a2
---
 src/media/media_encoder.cpp | 41 +++++++++++++++++++++++++++++++++++++
 src/media/media_encoder.h   |  3 +++
 2 files changed, 44 insertions(+)

diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp
index f985b1763e..50e8a21317 100644
--- a/src/media/media_encoder.cpp
+++ b/src/media/media_encoder.cpp
@@ -823,6 +823,28 @@ MediaEncoder::setBitrate(uint64_t br)
     return 1; // OK
 }
 
+int
+MediaEncoder::setPacketLoss(uint64_t pl)
+{
+    std::lock_guard<std::mutex> lk(encMutex_);
+    AVCodecContext* encoderCtx = getCurrentAudioAVCtx();
+    if (not encoderCtx)
+        return -1; // NOK
+
+    AVCodecID codecId = encoderCtx->codec_id;
+
+    if (not isDynPacketLossSupported(codecId))
+        return 0; // Restart needed
+
+    // Cap between 0 and 100
+    pl = std::clamp((int) pl, 0, 100);
+
+    // Change parameters on the fly
+    if (codecId == AV_CODEC_ID_OPUS)
+        av_opt_set_int(encoderCtx, "packet_loss", (int64_t) pl, AV_OPT_SEARCH_CHILDREN);
+    return 1; // OK
+}
+
 void
 MediaEncoder::initH264(AVCodecContext* encoderCtx, uint64_t br)
 {
@@ -997,6 +1019,16 @@ MediaEncoder::getCurrentVideoAVCtx()
     return nullptr;
 }
 
+AVCodecContext*
+MediaEncoder::getCurrentAudioAVCtx()
+{
+    for (auto it : encoders_) {
+        if (it->codec_type == AVMEDIA_TYPE_AUDIO)
+            return it;
+    }
+    return nullptr;
+}
+
 void
 MediaEncoder::stopEncoder()
 {
@@ -1027,6 +1059,15 @@ MediaEncoder::isDynBitrateSupported(AVCodecID codecid)
     return false;
 }
 
+bool
+MediaEncoder::isDynPacketLossSupported(AVCodecID codecid)
+{
+    if (codecid == AV_CODEC_ID_OPUS)
+        return true;
+
+    return false;
+}
+
 void
 MediaEncoder::readConfig(AVCodecContext* encoderCtx)
 {
diff --git a/src/media/media_encoder.h b/src/media/media_encoder.h
index 52c76a32c6..14e8268c76 100644
--- a/src/media/media_encoder.h
+++ b/src/media/media_encoder.h
@@ -105,6 +105,7 @@ public:
     const std::string& getVideoCodec() const { return videoCodec_; }
 
     int setBitrate(uint64_t br);
+    int setPacketLoss(uint64_t pl);
 
 #ifdef RING_ACCEL
     void enableAccel(bool enableAccel);
@@ -125,6 +126,7 @@ private:
     void openIOContext();
     void startIO();
     AVCodecContext* getCurrentVideoAVCtx();
+    AVCodecContext* getCurrentAudioAVCtx();
     void stopEncoder();
     AVCodecContext* initCodec(AVMediaType mediaType, AVCodecID avcodecId, uint64_t br);
     void initH264(AVCodecContext* encoderCtx, uint64_t br);
@@ -134,6 +136,7 @@ private:
     void initH263(AVCodecContext* encoderCtx, uint64_t br);
     void initOpus(AVCodecContext* encoderCtx);
     bool isDynBitrateSupported(AVCodecID codecid);
+    bool isDynPacketLossSupported(AVCodecID codecid);
     void initAccel(AVCodecContext* encoderCtx, uint64_t br);
     int getHWFrame(const std::shared_ptr<VideoFrame>& input, std::shared_ptr<VideoFrame>& output);
     std::shared_ptr<VideoFrame> getUnlinkedHWFrame(const VideoFrame& input);
-- 
GitLab