diff --git a/daemon/src/sip/Makefile.am b/daemon/src/sip/Makefile.am
index 16c87391cfc9abf537a8eba9435850323bdd7f72..8841259fd579ca989d7c225108683c126f1adc59 100644
--- a/daemon/src/sip/Makefile.am
+++ b/daemon/src/sip/Makefile.am
@@ -14,9 +14,7 @@ libsiplink_la_SOURCES = \
 		sipvoiplink.h \
 		siptransport.h \
 		sip_utils.cpp \
-		sip_utils.h \
-		sip_thread_client.h \
-		sip_thread_client.cpp
+		sip_utils.h
 
 if BUILD_SDES
 libsiplink_la_SOURCES+= sdes_negotiator.cpp \
diff --git a/daemon/src/sip/sip_thread_client.cpp b/daemon/src/sip/sip_thread_client.cpp
deleted file mode 100644
index e657e9efd9e0fc89c9f08102a4e25e4e30aacca0..0000000000000000000000000000000000000000
--- a/daemon/src/sip/sip_thread_client.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *  Copyright (C) 2012 Savoir-Faire Linux Inc.
- *  Author: Tristan Matthews <tristan.matthews@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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Additional permission under GNU GPL version 3 section 7:
- *
- *  If you modify this program, or any covered work, by linking or
- *  combining it with the OpenSSL project's OpenSSL library (or a
- *  modified version of that library), containing parts covered by the
- *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
- *  grants you additional permission to convey the resulting work.
- *  Corresponding Source for a non-source form of such a combination
- *  shall include the source code for the parts of OpenSSL used as well
- *  as that of the covered work.
- */
-
-#include "sip_thread_client.h"
-#include "logger.h"
-#include <cstring>
-
-SIPThreadClient::SIPThreadClient() : thread_(0), desc_()
-{
-    memset(desc_, 0, sizeof(desc_));
-    // We have to register the external thread so it can access the pjsip frameworks
-    if (pj_thread_register(NULL, desc_, &thread_) != PJ_SUCCESS)
-        ERROR("Could not register thread");
-}
-
-SIPThreadClient::~SIPThreadClient()
-{
-    if (thread_) {
-        WARN("Destroying thread handle");
-        if (pj_thread_join(thread_) != PJ_SUCCESS) {
-            ERROR("Error on thread join");
-        } else if (pj_thread_destroy(thread_) != PJ_SUCCESS) {
-            ERROR("Error on thread destroy");
-        }
-        thread_ = 0;
-    }
-}
diff --git a/daemon/src/sip/sip_thread_client.h b/daemon/src/sip/sip_thread_client.h
deleted file mode 100644
index e1aa36317fcc237ccf47270af1e8c9df96a91d29..0000000000000000000000000000000000000000
--- a/daemon/src/sip/sip_thread_client.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *  Copyright (C) 2011 Savoir-Faire Linux Inc.
- *  Author: Tristan Matthews <tristan.matthews@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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Additional permission under GNU GPL version 3 section 7:
- *
- *  If you modify this program, or any covered work, by linking or
- *  combining it with the OpenSSL project's OpenSSL library (or a
- *  modified version of that library), containing parts covered by the
- *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
- *  grants you additional permission to convey the resulting work.
- *  Corresponding Source for a non-source form of such a combination
- *  shall include the source code for the parts of OpenSSL used as well
- *  as that of the covered work.
- */
-
-#ifndef SIP_THREAD_CLIENT_H_
-#define SIP_THREAD_CLIENT_H_
-
-#include "pj/os.h"
-#include "noncopyable.h"
-
-class pj_thread_t;
-
-class SIPThreadClient {
-    private:
-        NON_COPYABLE(SIPThreadClient);
-        pj_thread_t *thread_;
-        pj_thread_desc desc_;
-
-    public:
-        SIPThreadClient();
-        ~SIPThreadClient();
-};
-
-#endif // SIP_THREAD_CLIENT_H_
diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp
index cb4cf0ed41e1a202965b74c8837005bd3ec17c4e..b9028fb11aa49e77f36cd0edaeae292a6c37c629 100644
--- a/daemon/src/sip/sipvoiplink.cpp
+++ b/daemon/src/sip/sipvoiplink.cpp
@@ -415,6 +415,10 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata)
 
 SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), sipAccountMap_(),
     sipCallMapMutex_(), sipCallMap_(), evThread_(this)
+#ifdef SFL_VIDEO
+    , keyframeRequestsMutex_()
+    , keyframeRequests_()
+#endif
 {
 #define TRY(ret) do { \
     if (ret != PJ_SUCCESS) \
@@ -561,6 +565,9 @@ bool SIPVoIPLink::getEvent()
 
     static const pj_time_val timeout = {0, 10};
     pjsip_endpt_handle_events(endpt_, &timeout);
+#ifdef SFL_VIDEO
+    dequeKeyframeRequests();
+#endif
     return handlingEvents_;
 }
 
@@ -1084,10 +1091,11 @@ SIPVoIPLink::getSipCall(const std::string& id)
 }
 
 SIPCall*
-SIPVoIPLink::tryGetSipCall(const std::string &id)
+SIPVoIPLink::tryGetSIPCall(const std::string &id)
 {
     if (not sipCallMapMutex_.tryEnterMutex()) {
         ERROR("Could not lock call map mutex");
+        sipCallMapMutex_.leaveMutex();
         return 0;
     }
     SipCallMap::iterator iter = sipCallMap_.find(id);
@@ -1278,13 +1286,35 @@ dtmfSend(SIPCall &call, char code, const std::string &dtmf)
 }
 
 #ifdef SFL_VIDEO
+// Called from a video thread
+void
+SIPVoIPLink::enqueueKeyframeRequest(const std::string &id)
+{
+    ost::MutexLock m(instance_->keyframeRequestsMutex_);
+    instance_->keyframeRequests_.push(id);
+}
+
+// Called from SIP event thread
+void
+SIPVoIPLink::dequeKeyframeRequests()
+{
+    int max_requests = 20;
+    while (not keyframeRequests_.empty() and max_requests--) {
+        ost::MutexLock m(keyframeRequestsMutex_);
+        const std::string &id(keyframeRequests_.front());
+        requestKeyframe(id);
+        keyframeRequests_.pop();
+    }
+}
+
+// Called from SIP event thread
 void
-SIPVoIPLink::requestFastPictureUpdate(const std::string &callID)
+SIPVoIPLink::requestKeyframe(const std::string &callID)
 {
     SIPCall *call = 0;
     const int tries = 10;
     for (int i = 0; !call and i < tries; ++i)
-        call = SIPVoIPLink::instance()->tryGetSipCall(callID);
+        call = SIPVoIPLink::instance()->tryGetSIPCall(callID);
     if (!call)
         return;
 
diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h
index 924915be9ed558784d7bf98040bb62b870b400f5..f261df94206b37fc197cb665d30fa3b75ff8dfd8 100644
--- a/daemon/src/sip/sipvoiplink.h
+++ b/daemon/src/sip/sipvoiplink.h
@@ -48,6 +48,9 @@
 #include <pjlib-util.h>
 #include <pjnath.h>
 #include <pjnath/stun_config.h>
+#ifdef SFL_VIDEO
+#include <queue>
+#endif
 
 #include "sipaccount.h"
 #include "voiplink.h"
@@ -283,9 +286,8 @@ class SIPVoIPLink : public VoIPLink {
         SipTransport sipTransport;
 
 #ifdef SFL_VIDEO
-        static void requestFastPictureUpdate(const std::string &callID);
+        static void enqueueKeyframeRequest(const std::string &callID);
 #endif
-
     private:
 
         NON_COPYABLE(SIPVoIPLink);
@@ -313,6 +315,13 @@ class SIPVoIPLink : public VoIPLink {
          */
         EventThread evThread_;
 
+#ifdef SFL_VIDEO
+        void dequeKeyframeRequests();
+        void requestKeyframe(const std::string &callID);
+        ost::Mutex keyframeRequestsMutex_;
+        std::queue<std::string> keyframeRequests_;
+#endif
+
         static bool destroyed_;
         static SIPVoIPLink *instance_;
 
diff --git a/daemon/src/video/video_receive_thread.cpp b/daemon/src/video/video_receive_thread.cpp
index 6ecb00d31c5eec2a107fd24c5feafc70d3df9cf2..6abd23b36090c9473fb4b43d7a80463ae0a11acf 100644
--- a/daemon/src/video/video_receive_thread.cpp
+++ b/daemon/src/video/video_receive_thread.cpp
@@ -32,7 +32,6 @@
 #include "video_receive_thread.h"
 #include "dbus/video_controls.h"
 #include "packet_handle.h"
-#include "sip/sip_thread_client.h"
 #include "check.h"
 
 // libav includes
@@ -157,10 +156,9 @@ void VideoReceiveThread::setup()
         ERROR("Could not remove %s", sdpFilename_.c_str());
 
     DEBUG("Finding stream info");
-    if (requestKeyFrameCallback_) {
-        sipThreadClient_.reset(new SIPThreadClient);
+    if (requestKeyFrameCallback_)
         requestKeyFrameCallback_(id_);
-    }
+
 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 8, 0)
     ret = av_find_stream_info(inputCtx_);
 #else
@@ -223,8 +221,7 @@ VideoReceiveThread::VideoReceiveThread(const std::string &id, const std::map<str
     args_(args), frameNumber_(0), inputDecoder_(0), decoderCtx_(0), rawFrame_(0),
     scaledPicture_(0), streamIndex_(-1), inputCtx_(0), imgConvertCtx_(0),
     dstWidth_(0), dstHeight_(0), sink_(), threadRunning_(false),
-    sdpFilename_(), bufferSize_(0), id_(id), interruptCb_(), requestKeyFrameCallback_(0),
-    sipThreadClient_(0)
+    sdpFilename_(), bufferSize_(0), id_(id), interruptCb_(), requestKeyFrameCallback_(0)
 {
     interruptCb_.callback = interruptCb;
     interruptCb_.opaque = this;
@@ -299,7 +296,6 @@ void VideoReceiveThread::run()
 VideoReceiveThread::~VideoReceiveThread()
 {
     threadRunning_ = false;
-    sipThreadClient_.reset(0);
     Manager::instance().getVideoControls()->stoppedDecoding(id_, sink_.openedName());
     // this calls join, which waits for the run() method (in separate thread) to return
     ost::Thread::terminate();
diff --git a/daemon/src/video/video_receive_thread.h b/daemon/src/video/video_receive_thread.h
index 4dd706ba3fcbddab576d85a4b77f93cc60c98da5..a908972b8d639ea780734ac3def5cd264f6e56f8 100644
--- a/daemon/src/video/video_receive_thread.h
+++ b/daemon/src/video/video_receive_thread.h
@@ -35,7 +35,6 @@
 #include <map>
 #include <string>
 #include <climits>
-#include <memory>
 #include "shm_sink.h"
 #include "noncopyable.h"
 
@@ -48,8 +47,6 @@ class AVCodecContext;
 class AVStream;
 class AVFormatContext;
 class AVFrame;
-class SIPThreadClient;
-
 namespace sfl_video {
 
 class VideoReceiveThread : public ost::Thread {
@@ -84,8 +81,6 @@ class VideoReceiveThread : public ost::Thread {
         const std::string id_;
         AVIOInterruptCB interruptCb_;
         void (* requestKeyFrameCallback_)(const std::string &);
-        // XXX: This must be allocated in the video thread, not the main thread
-        std::auto_ptr<SIPThreadClient> sipThreadClient_;
 
         void setup();
         void openDecoder();
diff --git a/daemon/src/video/video_rtp_session.cpp b/daemon/src/video/video_rtp_session.cpp
index 97c655a5b738b45198be45a790018ce702cccd3a..ceb0c25b7afa4cbc97be74cb73d739a56d420c75 100644
--- a/daemon/src/video/video_rtp_session.cpp
+++ b/daemon/src/video/video_rtp_session.cpp
@@ -133,7 +133,7 @@ void VideoRtpSession::start()
         if (receiveThread_.get())
             WARN("restarting video receiver");
         receiveThread_.reset(new VideoReceiveThread(callID_, rxArgs_));
-        receiveThread_->setRequestKeyFrameCallback(&SIPVoIPLink::requestFastPictureUpdate);
+        receiveThread_->setRequestKeyFrameCallback(&SIPVoIPLink::enqueueKeyframeRequest);
         receiveThread_->start();
     } else {
         DEBUG("Video receiving disabled");