diff --git a/src/account.cpp b/src/account.cpp
index 470bbb4720ffc4e8fc35bc1fa63443fd962e4c98..2082bc319ba9c0ea5e795829ca61c3b47f3d4900 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -41,6 +41,7 @@
 #include "fileutils.h"
 #include "config/yamlparser.h"
 #include "system_codec_container.h"
+#include "vcard.h"
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -65,10 +66,11 @@ namespace jami {
 // the data directory prefix that must be set at build time.
 const std::string Account::DEFAULT_USER_AGENT = Account::getDefaultUserAgent();
 
-Account::Account(const std::string& accountID)
+Account::Account(const std::string& accountId)
     : rand(Manager::instance().getSeededRandomEngine())
-    , accountID_(accountID)
+    , accountID_(accountId)
     , systemCodecContainer_(getSystemCodecContainer())
+    , idPath_(fileutils::get_data_dir() / accountId)
 {
     // Initialize the codec order, used when creating a new account
     loadDefaultCodecs();
@@ -180,6 +182,20 @@ Account::getVolatileAccountDetails() const
             {libjami::Account::VolatileProperties::ACTIVE, active_ ? TRUE_STR : FALSE_STR}};
 }
 
+std::map<std::string, std::string>
+Account::getProfileVcard() const
+{
+    try {
+        auto path = idPath_ / "profile.vcf";
+        if (!std::filesystem::exists(path))
+            return {};
+        return vCard::utils::toMap(fileutils::loadTextFile(path));
+    } catch (const std::exception& e) {
+        JAMI_ERROR("Error reading profile: {}", e.what());
+        return {};
+    }
+}
+
 bool
 Account::hasActiveCodec(MediaType mediaType) const
 {
diff --git a/src/account.h b/src/account.h
index 8db8c219fe700d2b37862488c0f26416692ab546..0a738f7b31d4527d6a3585c90d2f95dce3a64530 100644
--- a/src/account.h
+++ b/src/account.h
@@ -149,6 +149,8 @@ public:
 
     virtual std::string_view getAccountType() const = 0;
 
+    const std::filesystem::path& getPath() const { return idPath_; }
+
     /**
      * Returns true if this is the IP2IP account
      */
@@ -208,7 +210,9 @@ public:
 
     virtual std::map<std::string, std::string> getNearbyPeers() const { return {}; }
 
-    virtual void updateProfile(const std::string& /*displayName*/,  const std::string& /*avatar*/,const uint64_t& /*flag*/) {}
+    virtual void updateProfile(const std::string& /*displayName*/,  const std::string& /*avatar*/,const uint64_t& /*flag*/) = 0;
+
+    std::map<std::string, std::string> getProfileVcard() const;
 
     /**
      * Return the status corresponding to the token.
@@ -479,6 +483,11 @@ protected:
      */
     std::vector<std::shared_ptr<SystemCodecInfo>> accountCodecInfoList_;
 
+    /**
+     * path to account
+     */
+    std::filesystem::path idPath_ {};
+
     /**
      * Ringtone .au file used for this account
      */
diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp
index b4d5098366efbd4c26786211189762c0acb10000..076526e7c314104c3e7660fb8d76e4c113f51c61 100644
--- a/src/client/configurationmanager.cpp
+++ b/src/client/configurationmanager.cpp
@@ -296,7 +296,9 @@ getNearbyPeers(const std::string& accountId)
 void
 updateProfile(const std::string& accountId,const std::string& displayName, const std::string& avatar,const uint64_t& flag)
 {
-    jami::Manager::instance().updateProfile(accountId, displayName, avatar, flag);
+    if (const auto acc = jami::Manager::instance().getAccount(accountId)){
+        acc->updateProfile(displayName, avatar, flag);
+    }
 }
 
 int
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index 96aaebab0cb01cd594d0b79001da5007293e0ab3..8cf817f862c24c2f23e82ab861a7fc0497ecb6c0 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -260,7 +260,6 @@ dhtStatusStr(dht::NodeStatus status)
 
 JamiAccount::JamiAccount(const std::string& accountId)
     : SIPAccountBase(accountId)
-    , idPath_(fileutils::get_data_dir() / accountId)
     , cachePath_(fileutils::get_cache_dir() / accountId)
     , dataPath_(cachePath_ / "values")
     , certStore_ {std::make_unique<dhtnet::tls::CertificateStore>(idPath_, Logger::dhtLogger())}
@@ -3393,18 +3392,6 @@ JamiAccount::sendProfileToPeers()
     }
 }
 
-std::map<std::string, std::string>
-JamiAccount::getProfileVcard() const
-{
-    const auto& path = idPath_ / "profile.vcf";
-
-    if (!std::filesystem::exists(path)) {
-        return {};
-    }
-
-    return vCard::utils::toMap(fileutils::loadTextFile(path));
-}
-
 void
 JamiAccount::updateProfile(const std::string& displayName,
                            const std::string& avatar,
diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h
index 316d2ed185089ad65744df8d7fad002d03a1673d..ca36fa26dca1ee9930aebe4ded3e8104ff51db16 100644
--- a/src/jamidht/jamiaccount.h
+++ b/src/jamidht/jamiaccount.h
@@ -119,8 +119,6 @@ public:
         return std::static_pointer_cast<JamiAccount const>(shared_from_this());
     }
 
-    const std::filesystem::path& getPath() const { return idPath_; }
-
     const JamiAccountConfig& config() const
     {
         return *static_cast<const JamiAccountConfig*>(&Account::config());
@@ -420,7 +418,6 @@ public:
      */
     std::map<std::string, std::string> getNearbyPeers() const override;
 
-    std::map<std::string, std::string> getProfileVcard() const;
     void sendProfileToPeers();
 
     /**
@@ -708,7 +705,6 @@ private:
         const Uri& uri, const std::vector<libjami::MediaMap>& mediaList);
     std::shared_ptr<SIPCall> createSubCall(const std::shared_ptr<SIPCall>& mainCall);
 
-    std::filesystem::path idPath_ {};
     std::filesystem::path cachePath_ {};
     std::filesystem::path dataPath_ {};
 
diff --git a/src/manager.cpp b/src/manager.cpp
index 46c062a9a8fdc6d870fbffa43332c3e578f5101e..a04b1336958819dd2509a9722e44983fde7aaaf6 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -3264,14 +3264,6 @@ Manager::getNearbyPeers(const std::string& accountID)
     return {};
 }
 
-void
-Manager::updateProfile(const std::string& accountID,const std::string& displayName, const std::string& avatar,const uint64_t& flag)
-{
-    if (const auto acc = getAccount<JamiAccount>(accountID))
-        acc->updateProfile(displayName,avatar,flag);
-}
-
-
 void
 Manager::setDefaultModerator(const std::string& accountID, const std::string& peerURI, bool state)
 {
diff --git a/src/manager.h b/src/manager.h
index 898aedcc3c5f1765eb54fc939cddceb0cb8debc3..cc4fab98a0fa29faac9526d33a227487e7b68e33 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -811,8 +811,6 @@ public:
 
     std::map<std::string, std::string> getNearbyPeers(const std::string& accountID);
 
-    void updateProfile(const std::string& accountID,const std::string& displayName,const std::string& avatar,const uint64_t& flag);
-
 #ifdef ENABLE_VIDEO
     /**
      * Create a new SinkClient instance, store it in an internal cache as a weak_ptr
diff --git a/src/media/audio/audiolayer.cpp b/src/media/audio/audiolayer.cpp
index 150ea80ac2984b0d2c14466d81611ea4861c44e4..98c50270cb0121931922cd1de73914ac17d9fcea 100644
--- a/src/media/audio/audiolayer.cpp
+++ b/src/media/audio/audiolayer.cpp
@@ -282,8 +282,7 @@ AudioLayer::getToRing(AudioFormat format, size_t writableSamples)
         auto fileformat = fileToPlay->getFormat();
         bool resample = format != fileformat;
 
-        size_t readableSamples = resample ? (rational<size_t>(writableSamples, format.sample_rate)
-                                             * (size_t) fileformat.sample_rate)
+        size_t readableSamples = resample ? rational<size_t>(writableSamples * (size_t)fileformat.sample_rate, format.sample_rate)
                                                 .real<size_t>()
                                           : writableSamples;
 
diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp
index 3ca7b11a717dad9947e636b882c83d71b732dc33..9f0bb00169d8886b26eda529669d6ded81f7d003 100644
--- a/src/media/media_decoder.cpp
+++ b/src/media/media_decoder.cpp
@@ -706,7 +706,7 @@ MediaDecoder::decode(AVPacket& packet)
         if (emulateRate_ and packetTimestamp != AV_NOPTS_VALUE) {
             auto startTime = avStream_->start_time == AV_NOPTS_VALUE ? 0 : avStream_->start_time;
             rational<double> frame_time = rational<double>(getTimeBase())
-                                          * (packetTimestamp - startTime);
+                                          * rational<double>(packetTimestamp - startTime);
             auto target_relative = static_cast<std::int64_t>(frame_time.real() * 1e6);
             auto target_absolute = startTime_ + target_relative;
             if (target_relative < seekTime_) {
diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp
index 46bdc76326d9b0ba934bc5ad47282b7f3ca7e244..db928c69c8656c87bf4c54c98100aeac0e8003da 100644
--- a/src/sip/sipaccount.cpp
+++ b/src/sip/sipaccount.cpp
@@ -23,6 +23,10 @@
 
 #include "compiler_intrinsics.h"
 
+#include "vcard.h"
+#include "base64.h"
+#include "fileutils.h"
+
 #include "sdp.h"
 #include "sip/sipvoiplink.h"
 #include "sip/sipcall.h"
@@ -141,6 +145,56 @@ SIPAccount::~SIPAccount() noexcept
     delete presence_;
 }
 
+void
+SIPAccount::updateProfile(const std::string& displayName,
+                          const std::string& avatar,
+                          const uint64_t& flag)
+{
+    auto vCardPath = idPath_ / "profile.vcf";
+
+    auto profile = getProfileVcard();
+    if (profile.empty()) {
+        profile = vCard::utils::initVcard();
+    }
+    profile["FN"] = displayName;
+
+    if (flag == 0) {
+        const auto& avatarPath = std::filesystem::path(avatar);
+        if (std::filesystem::exists(avatarPath)) {
+            try {
+                const auto& base64 = jami::base64::encode(fileutils::loadFile(avatarPath));
+                profile["PHOTO;ENCODING=BASE64;TYPE=PNG"] = base64;
+            } catch (const std::exception& e) {
+                JAMI_ERROR("Failed to load avatar: {}", e.what());
+            }
+        } else if (avatarPath.empty()) {
+            profile["PHOTO;ENCODING=BASE64;TYPE=PNG"] = "";
+        }
+    } else if (flag == 1) {
+        profile["PHOTO;ENCODING=BASE64;TYPE=PNG"] = avatar;
+    }
+
+    // nothing happens to the profile photo if the avatarPath is invalid
+    // and not empty. So far it seems to be the best default behavior.
+
+    const std::string& vCard = vCard::utils::toString(profile);
+
+    try {
+        auto tmpPath = vCardPath;
+        tmpPath += ".tmp";
+        std::ofstream file(tmpPath);
+        if (file.is_open()) {
+            file << vCard;
+            file.close();
+            std::filesystem::rename(tmpPath, vCardPath);
+        } else {
+            JAMI_ERROR("Unable to open file for writing: {}", tmpPath);
+        }
+    } catch (const std::exception& e) {
+        JAMI_ERROR("Error writing profile: {}", e.what());
+    }
+}
+
 std::shared_ptr<SIPCall>
 SIPAccount::newIncomingCall(const std::string& from UNUSED,
                             const std::vector<libjami::MediaMap>& mediaList,
diff --git a/src/sip/sipaccount.h b/src/sip/sipaccount.h
index de676f6df86a63745029e6cf08986a190e9733e6..05cee9a1b4e679f2d9b485658e11a5fef71e493a 100644
--- a/src/sip/sipaccount.h
+++ b/src/sip/sipaccount.h
@@ -127,6 +127,11 @@ public:
      */
     void loadConfig() override;
 
+    /**
+     * updates SIP account profile
+     */
+    void updateProfile(const std::string& displayName, const std::string& avatar, const uint64_t& flag) override;
+
     /**
      * Initialize the SIP voip link with the account parameters and send registration
      */