diff --git a/src/media/media_codec.h b/src/media/media_codec.h
index ea6a6680d69745d243b5c19b8f9021c65168e1c1..19f845ec3b76056c99284ac48fb074e0e7e56d86 100644
--- a/src/media/media_codec.h
+++ b/src/media/media_codec.h
@@ -278,6 +278,7 @@ struct MediaDescription {
 
     /** Video parameters */
     std::string parameters {};
+    bool auto_quality {false};
 
     /** Crypto parameters */
     CryptoAttribute crypto {};
diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp
index 0ec2230ae3daaeaba2b5d914dc7cd4196c3ab701..f5f46d7a5abadeb7d1c41482c106c8da3b557be5 100644
--- a/src/media/media_encoder.cpp
+++ b/src/media/media_encoder.cpp
@@ -118,6 +118,8 @@ MediaEncoder::setOptions(const MediaDescription& args)
 
     if (not args.parameters.empty())
         libav_utils::setDictValue(&options_, "parameters", args.parameters);
+
+    auto_quality = args.auto_quality;
 }
 
 void
@@ -552,7 +554,7 @@ MediaEncoder::prepareEncoderContext(AVCodec* outputCodec, bool is_video)
 void
 MediaEncoder::forcePresetX264(AVCodecContext* encoderCtx)
 {
-    const char *speedPreset = "ultrafast";
+    const char *speedPreset = "veryfast";
     if (av_opt_set(encoderCtx, "preset", speedPreset, AV_OPT_SEARCH_CHILDREN))
         JAMI_WARN("Failed to set x264 preset '%s'", speedPreset);
     const char *tune = "zerolatency";
@@ -739,31 +741,40 @@ MediaEncoder::setBitrate(uint64_t br)
     else if(codecId == AV_CODEC_ID_MPEG4)
         initMPEG4(encoderCtx, br);
     else {
-        stopEncoder();
-        encoderCtx = initCodec(codecType, codecId, NULL, br);
-        if (avcodec_open2(encoderCtx, outputCodec_, &options_) < 0)
-            throw MediaEncoderException("Could not open encoder");
+        // restart encoder on runtime doesn't work for VP8
+        // stopEncoder();
+        // encoderCtx = initCodec(codecType, codecId, NULL, br);
+        // if (avcodec_open2(encoderCtx, outputCodec_, &options_) < 0)
+        //     throw MediaEncoderException("Could not open encoder");
     }
 }
 
 void
 MediaEncoder::initH264(AVCodecContext* encoderCtx, uint64_t br)
 {
-    uint64_t maxBitrate = 1000 * br;
-    uint8_t crf = (uint8_t) std::round(LOGREG_PARAM_A + log(pow(maxBitrate, LOGREG_PARAM_B)));     // CRF = A + B*ln(maxBitrate)
-    uint64_t bufSize = 2 * maxBitrate;
-#ifdef RING_ACCEL
-    if (accel_) {
-        bufSize = 2 * maxBitrate;
-        encoderCtx->bit_rate = maxBitrate;
+    // If auto quality disabled use CRF mode
+    if(not auto_quality) {
+        uint64_t maxBitrate = 1000 * br;
+        uint8_t crf = (uint8_t) std::round(LOGREG_PARAM_A + log(pow(maxBitrate, LOGREG_PARAM_B)));     // CRF = A + B*ln(maxBitrate)
+        uint64_t bufSize = maxBitrate * 2;
+
+        av_opt_set_int(encoderCtx, "crf", crf, AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_int(encoderCtx, "b", maxBitrate, AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_int(encoderCtx, "maxrate", maxBitrate, AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_int(encoderCtx, "minrate", -1, AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_int(encoderCtx, "bufsize", bufSize, AV_OPT_SEARCH_CHILDREN);
+        JAMI_DBG("H264 encoder setup: crf=%u, maxrate=%lu, bufsize=%lu", crf, maxBitrate, bufSize);
     }
-#endif
+    // If auto quality enabled use CRB mode
+    else {
+        av_opt_set_int(encoderCtx, "b", br * 1000, AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_int(encoderCtx, "maxrate", br * 1000, AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_int(encoderCtx, "minrate", br * 1000, AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_int(encoderCtx, "bufsize", br * 500, AV_OPT_SEARCH_CHILDREN);
+        av_opt_set_int(encoderCtx, "crf", -1, AV_OPT_SEARCH_CHILDREN);
 
-    libav_utils::setDictValue(&options_, "crf", std::to_string(crf));
-    av_opt_set_int(encoderCtx, "crf", crf, AV_OPT_SEARCH_CHILDREN);
-    encoderCtx->rc_buffer_size = bufSize;
-    encoderCtx->rc_max_rate = maxBitrate;
-    JAMI_DBG("H264 encoder setup: crf=%u, maxrate=%lu, bufsize=%lu", crf, maxBitrate, bufSize);
+        JAMI_DBG("H264 encoder setup cbr: bitrate=%lu kbit/s", br);
+    }
 }
 
 void
diff --git a/src/media/media_encoder.h b/src/media/media_encoder.h
index 800ec4bc955fced8035156a4b8af11ef828e1daa..0b978589aeb2fef99a97b471bffeae586aed4e8f 100644
--- a/src/media/media_encoder.h
+++ b/src/media/media_encoder.h
@@ -132,6 +132,7 @@ private:
     unsigned int currentVideoCodecID_ {0};
     AVCodec* outputCodec_ = nullptr;
     std::mutex encMutex_;
+    bool auto_quality {false};
 
     void initH264(AVCodecContext* encoderCtx, uint64_t br);
     void initVP8(AVCodecContext* encoderCtx, uint64_t br);
diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp
index 2aad2cc5ea4e6ad01a5d5495f830a0e10346e3ac..14fd9df8300e7df176dd3d1e9901a3ebf210550e 100644
--- a/src/media/video/video_rtp_session.cpp
+++ b/src/media/video/video_rtp_session.cpp
@@ -128,6 +128,12 @@ void VideoRtpSession::startSender()
 
         // be sure to not send any packets before saving last RTP seq value
         socketPair_->stopSendOp();
+
+        auto codecVideo = std::static_pointer_cast<jami::AccountVideoCodecInfo>(send_.codec);
+        auto autoQuality = codecVideo->isAutoQualityEnabled;
+
+        send_.auto_quality = autoQuality;
+
         if (sender_)
             initSeqVal_ = sender_->getLastSeqValue() + 10; // Skip a few sequences to make nvenc happy on a sender restart
         try {
@@ -145,8 +151,6 @@ void VideoRtpSession::startSender()
         lastMediaRestart_ = clock::now();
         last_REMB_inc_ = clock::now();
         last_REMB_dec_ = clock::now();
-        auto codecVideo = std::static_pointer_cast<jami::AccountVideoCodecInfo>(send_.codec);
-        auto autoQuality = codecVideo->isAutoQualityEnabled;
         if (autoQuality and not rtcpCheckerThread_.isRunning())
             rtcpCheckerThread_.start();
         else if (not autoQuality and rtcpCheckerThread_.isRunning())
@@ -517,7 +521,7 @@ VideoRtpSession::setNewBitrate(unsigned int newBR)
 
 #if __ANDROID__
     auto input_device = std::static_pointer_cast<VideoInput>(videoLocal_);
-    emitSignal<DRing::VideoSignal::SetBitrate>(input_device->getParams().name, (int)videoBitrateInfo_.videoBitrateCurrent);
+    emitSignal<DRing::VideoSignal::SetBitrate>(input_device->getParams().name, (int)newBR);
 #endif
 
         // If encoder no longer exist do nothing