diff --git a/MainPage.xaml.cpp b/MainPage.xaml.cpp
index 191ae3b633fcbce0616252082e0e786bf871c3d4..bdcbb29d3437a4f6a8285ee664b56d61553da05b 100644
--- a/MainPage.xaml.cpp
+++ b/MainPage.xaml.cpp
@@ -106,7 +106,6 @@ RingClientUWP::MainPage::showFrame(Windows::UI::Xaml::Controls::Frame^ frame)
         _navGrid_->SetRow(_welcomeFrame_, 1);
     } else if (frame == _videoFrame_) {
         _navGrid_->SetRow(_videoFrame_, 1);
-        dynamic_cast<VideoPage^>(_videoFrame_->Content)->updatePageContent();
     } else if (frame == _messageTextFrame_) {
         _navGrid_->SetRow(_messageTextFrame_, 1);
     }
@@ -260,3 +259,37 @@ void RingClientUWP::MainPage::OnstateChange(Platform::String ^callId, RingClient
     }
 
 }
+
+void
+MainPage::Application_Suspending(Object^, Windows::ApplicationModel::SuspendingEventArgs^ e)
+{
+    WriteLine("Application_Suspending");
+    if (Frame->CurrentSourcePageType.Name ==
+        Interop::TypeName(MainPage::typeid).Name)
+    {
+        if (Video::VideoManager::instance->captureManager()->captureTaskTokenSource)
+            Video::VideoManager::instance->captureManager()->captureTaskTokenSource->cancel();
+        //displayInformation->OrientationChanged -= displayInformationEventToken;
+        auto deferral = e->SuspendingOperation->GetDeferral();
+        Video::VideoManager::instance->captureManager()->CleanupCameraAsync()
+            .then([this, deferral]() {
+            deferral->Complete();
+        });
+    }
+}
+
+void
+MainPage::Application_VisibilityChanged(Object^ sender, VisibilityChangedEventArgs^ e)
+{
+    if (e->Visible)
+    {
+        WriteLine("->Visible");
+        if (Video::VideoManager::instance->captureManager()->isInitialized) {
+            Video::VideoManager::instance->captureManager()->InitializeCameraAsync();
+        }
+    }
+    else
+    {
+        WriteLine("->Invisible");
+    }
+}

diff --git a/MainPage.xaml.h b/MainPage.xaml.h
index d97fd59e7bcd4eb15669c02ee5a0cd55e311ecf2..554ae31ba52effa5f105435c5978e8a29c02b888 100644
--- a/MainPage.xaml.h
+++ b/MainPage.xaml.h
@@ -45,6 +45,10 @@ protected:
     void OnResize(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e);
 
 private:
+    // event handlers
+    void Application_Suspending(Object^, Windows::ApplicationModel::SuspendingEventArgs^ e);
+    void Application_VisibilityChanged(Object^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ e);
+
     // Multi-monitor, DPI, scale factor change, and window resize detection
     void DisplayProperties_DpiChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
     Windows::Foundation::EventRegistrationToken dpiChangedtoken;
@@ -58,4 +62,4 @@ private:
     void OnpressHangUpCall();
     void OnstateChange(Platform::String ^callId, RingClientUWP::CallStatus state, int code);
 };
-}
\ No newline at end of file
+}
diff --git a/RingD.cpp b/RingD.cpp
index 2508fb8d2d5f1ce461a82e78c4398f2a7b681d88..38033d87208fb76b6197d078c8058dc8dedfaf64 100644
--- a/RingD.cpp
+++ b/RingD.cpp
@@ -23,6 +23,7 @@
 #include "callmanager_interface.h"
 #include "configurationmanager_interface.h"
 #include "presencemanager_interface.h"
+#include "videomanager_interface.h"
 #include "fileutils.h"
 #include "account_schema.h"
 #include "account_const.h"
@@ -32,6 +33,9 @@
 using namespace Windows::ApplicationModel::Core;
 using namespace Windows::Storage;
 using namespace Windows::UI::Core;
+using namespace Windows::Media;
+using namespace Windows::Media::MediaProperties;
+using namespace Windows::Media::Capture;
 
 using namespace RingClientUWP;
 using namespace RingClientUWP::Utils;
@@ -311,14 +315,7 @@ RingClientUWP::RingD::startDaemon()
                     RingDebug::instance->print(toto);
                 }));
             })
-            /* to remove from daemon API, this callback is never used */
-            //DRing::exportable_callback<DRing::CallSignal::NewCallCreated>([&](
-            //            const std::string& accountId,
-            //            const std::string& callId,
-            //            const std::string& to)
-            //{ /*...*/ })
         };
-
         registerCallHandlers(callHandlers);
 
         std::map<std::string, SharedCallback> getAppPathHandler =
@@ -330,6 +327,91 @@ RingClientUWP::RingD::startDaemon()
         };
         registerCallHandlers(getAppPathHandler);
 
+        std::map<std::string, SharedCallback> incomingVideoHandlers =
+        {
+            DRing::exportable_callback<DRing::VideoSignal::DeviceEvent>
+            ([this]() {
+                MSG_("<DeviceEvent>");
+            }),
+            DRing::exportable_callback<DRing::VideoSignal::DecodingStarted>
+            ([this](const std::string &id, const std::string &shmPath, int width, int height, bool isMixer) {
+                MSG_("<DecodingStarted>");
+                Video::VideoManager::instance->rendererManager()->startedDecoding(
+                    Utils::toPlatformString(id),
+                    width,
+                    height);
+            }),
+            DRing::exportable_callback<DRing::VideoSignal::DecodingStopped>
+            ([this](const std::string &id, const std::string &shmPath, bool isMixer) {
+                MSG_("<DecodingStopped>");
+                MSG_("Removing renderer id:" + id);
+                /*auto Id = Utils::toPlatformString(id);
+                auto renderer = Video::VideoManager::instance->rendererManager()->renderer(Id);
+                if (renderer)
+                    renderer->isRendering = false;*/
+                Video::VideoManager::instance->rendererManager()->removeRenderer(Utils::toPlatformString(id));
+            })
+        };
+        registerVideoHandlers(incomingVideoHandlers);
+
+        using namespace Video;
+        std::map<std::string, SharedCallback> outgoingVideoHandlers =
+        {
+            DRing::exportable_callback<DRing::VideoSignal::GetCameraInfo>
+            ([this](const std::string& device,
+                    std::vector<std::string> *formats,
+                    std::vector<unsigned> *sizes,
+                    std::vector<unsigned> *rates) {
+                MSG_("\n<GetCameraInfo>\n");
+                auto device_list = VideoManager::instance->captureManager()->deviceList;
+
+                for (unsigned int i = 0; i < device_list->Size; i++) {
+                    auto dev = device_list->GetAt(i);
+                    if (device == Utils::toString(dev->name())) {
+                        auto channel = dev->channel();
+                        Vector<Video::Resolution^>^ resolutions = channel->resolutionList();
+                        for (auto res : resolutions) {
+                            formats->emplace_back(Utils::toString(res->format()));
+                            sizes->emplace_back(res->size()->width());
+                            sizes->emplace_back(res->size()->height());
+                            rates->emplace_back(res->activeRate()->value());
+                        }
+                    }
+                }
+            }),
+            DRing::exportable_callback<DRing::VideoSignal::SetParameters>
+            ([this](const std::string& device,
+                    std::string format,
+                    const int width,
+                    const int height,
+                    const int rate) {
+                MSG_("\n<SetParameters>\n");
+                VideoManager::instance->captureManager()->activeDevice->SetDeviceProperties(
+                    Utils::toPlatformString(format),width,height,rate);
+            }),
+            DRing::exportable_callback<DRing::VideoSignal::StartCapture>
+            ([&](const std::string& device) {
+                MSG_("\n<StartCapture>\n");
+                dispatcher->RunAsync(CoreDispatcherPriority::Normal,
+                ref new DispatchedHandler([=]() {
+                    VideoManager::instance->captureManager()->InitializeCameraAsync();
+                    VideoManager::instance->captureManager()->videoFrameCopyInvoker->Start();
+                }));
+            }),
+            DRing::exportable_callback<DRing::VideoSignal::StopCapture>
+            ([&]() {
+                MSG_("\n<StopCapture>\n");
+                dispatcher->RunAsync(CoreDispatcherPriority::Normal,
+                ref new DispatchedHandler([=]() {
+                    VideoManager::instance->captureManager()->StopPreviewAsync();
+                    if (VideoManager::instance->captureManager()->captureTaskTokenSource)
+                        VideoManager::instance->captureManager()->captureTaskTokenSource->cancel();
+                    VideoManager::instance->captureManager()->videoFrameCopyInvoker->Stop();
+                }));
+            })
+        };
+        registerVideoHandlers(outgoingVideoHandlers);
+
         DRing::init(static_cast<DRing::InitFlag>(DRing::DRING_FLAG_CONSOLE_LOG |
                     DRing::DRING_FLAG_DEBUG));
 
@@ -338,8 +420,7 @@ RingClientUWP::RingD::startDaemon()
             return;
         }
         else {
-            if (!hasConfig)
-            {
+            if (!hasConfig) {
                 tasksList_.push(ref new RingD::Task(Request::AddRingAccount));
                 tasksList_.push(ref new RingD::Task(Request::AddSIPAccount));
             }
diff --git a/RingDebug.h b/RingDebug.h
index 83c13880717556375c6df624d4bdd3af98f41556..2398085ca8244bb672572f48934ecd60c150cd0c 100644
--- a/RingDebug.h
+++ b/RingDebug.h
@@ -54,6 +54,20 @@ private:
     RingDebug() {}; // singleton
 };
 
+void WriteLine(String^ str)
+{
+    std::wstringstream wStringstream;
+    wStringstream << str->Data() << "\n";
+    OutputDebugString(wStringstream.str().c_str());
+}
+
+void WriteException(Exception^ ex)
+{
+    std::wstringstream wStringstream;
+    wStringstream << "0x" << ex->HResult << ": " << ex->Message->Data();
+    OutputDebugString(wStringstream.str().c_str());
+}
+
 #define MSG_(cstr) CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Low, \
 ref new DispatchedHandler([=]() { RingDebug::instance->print(cstr); }))
 
diff --git a/Utils.h b/Utils.h
index 2f6e4f4514aa1304df4dcdc0234cb2abcb36723d..879542c1f2239a3a3dc4cc00af87d09816bb6f3a 100644
--- a/Utils.h
+++ b/Utils.h
@@ -20,8 +20,11 @@
 #include <pch.h>
 
 using namespace Platform;
+using namespace Platform::Collections;
 using namespace Windows::Storage;
 
+typedef Windows::UI::Xaml::Visibility VIS;
+
 namespace RingClientUWP
 {
 namespace Utils
@@ -50,7 +53,8 @@ fileExists(StorageFolder^ folder, String^ fileName)
     });
 }
 
-std::string makeString(const std::wstring& wstr)
+inline std::string
+makeString(const std::wstring& wstr)
 {
     auto wideData = wstr.c_str();
     int bufferSize = WideCharToMultiByte(CP_UTF8, 0, wideData, -1, nullptr, 0, NULL, NULL);
@@ -65,7 +69,8 @@ std::string makeString(const std::wstring& wstr)
     return std::string(utf8.get());
 }
 
-std::wstring makeWString(const std::string& str)
+inline std::wstring
+makeWString(const std::string& str)
 {
     auto utf8Data = str.c_str();
     int bufferSize = MultiByteToWideChar(CP_UTF8, 0, utf8Data, -1, nullptr, 0);
@@ -80,19 +85,22 @@ std::wstring makeWString(const std::string& str)
     return std::wstring(wide.get());;
 }
 
-std::string toString(Platform::String ^str)
+inline std::string
+toString(Platform::String ^str)
 {
     std::wstring wsstr(str->Data());
     return makeString(wsstr);
 }
 
-Platform::String^ toPlatformString(const std::string& str)
+inline Platform::String^
+toPlatformString(const std::string& str)
 {
     std::wstring wsstr = makeWString(str);
     return ref new Platform::String(wsstr.c_str(), wsstr.length());
 }
 
-Platform::String^ Trim(Platform::String^ s)
+Platform::String^
+Trim(Platform::String^ s)
 {
     const WCHAR* first = s->Begin();
     const WCHAR* last = s->End();
@@ -107,7 +115,8 @@ Platform::String^ Trim(Platform::String^ s)
 }
 
 /* fix some issue in the daemon --> <...@...> */
-Platform::String^ TrimRingId(Platform::String^ s)
+Platform::String^
+TrimRingId(Platform::String^ s)
 {
     const WCHAR* first = s->Begin();
     const WCHAR* last = s->End();
@@ -125,7 +134,8 @@ Platform::String^ TrimRingId(Platform::String^ s)
 }
 
 /* fix some issue in the daemon -->  remove "@..." */
-Platform::String^ TrimRingId2(Platform::String^ s)
+Platform::String^
+TrimRingId2(Platform::String^ s)
 {
     const WCHAR* first = s->Begin();
     const WCHAR* last = s->End();
@@ -138,7 +148,8 @@ Platform::String^ TrimRingId2(Platform::String^ s)
     return ref new Platform::String(first, static_cast<unsigned int>(last - first));
 }
 
-Platform::String^ GetNewGUID()
+Platform::String^
+GetNewGUID()
 {
     GUID result;
     HRESULT hr = CoCreateGuid(&result);
@@ -159,5 +170,31 @@ getStringFromFile(const std::string& filename)
         (std::istreambuf_iterator<char>()));
 }
 
+inline Map<String^,String^>^
+convertMap(const std::map<std::string, std::string>& m)
+{
+    auto temp = ref new Map<String^,String^>;
+    for (const auto& pair : m) {
+        temp->Insert(
+            Utils::toPlatformString(pair.first),
+            Utils::toPlatformString(pair.second)
+        );
+    }
+    return temp;
+}
+
+inline std::map<std::string, std::string>
+convertMap(Map<String^,String^>^ m)
+{
+    std::map<std::string, std::string> temp;
+    for (const auto& pair : m) {
+        temp.insert(
+            std::make_pair(
+                Utils::toString(pair->Key),
+                Utils::toString(pair->Value)));
+    }
+    return temp;
+}
+
 }
 }
diff --git a/Video.cpp b/Video.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..84ad568d15827ba868382daf3428df16dd1e9108
--- /dev/null
+++ b/Video.cpp
@@ -0,0 +1,282 @@
+/**************************************************************************
+* Copyright (C) 2016 by Savoir-faire Linux                                *
+* Author: J�ger Nicolas <nicolas.jager@savoirfairelinux.com>              *
+* Author: Traczyk Andreas <andreas.traczyk@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, see <http://www.gnu.org/licenses/>.   *
+**************************************************************************/
+
+#include "pch.h"
+
+#include "Video.h"
+
+using namespace RingClientUWP;
+using namespace Video;
+
+using namespace Platform;
+
+/************************************************************
+ *                                                          *
+ *                         Size                             *
+ *                                                          *
+ ***********************************************************/
+
+unsigned int
+Video::Size::width()
+{
+    return m_Width;
+}
+
+unsigned int
+Video::Size::height()
+{
+    return m_Height;
+}
+
+void
+Video::Size::setWidth(unsigned int width)
+{
+    m_Width = width;
+}
+
+void
+Video::Size::setHeight(unsigned int height)
+{
+    m_Height = height;
+}
+
+/************************************************************
+ *                                                          *
+ *                         Rate                             *
+ *                                                          *
+ ***********************************************************/
+
+String^
+Rate::name()
+{
+    return m_name;
+}
+
+unsigned int
+Rate::value()
+{
+    return m_value;
+}
+
+void
+Rate::setName(String^ name)
+{
+    m_name = name;
+}
+
+void
+Rate::setValue(unsigned int value)
+{
+    m_value = value;
+}
+
+/************************************************************
+ *                                                          *
+ *                         Channel                          *
+ *                                                          *
+ ***********************************************************/
+Channel::Channel()
+{
+    m_validResolutions = ref new Vector<Resolution^>();
+}
+
+String^
+Channel::name()
+{
+    return m_name;
+}
+
+Resolution^
+Channel::currentResolution()
+{
+    return m_currentResolution;
+}
+
+void
+Channel::setName(String^ name)
+{
+    m_name = name;
+}
+
+void
+Channel::setCurrentResolution(Resolution^ currentResolution)
+{
+    m_currentResolution = currentResolution;
+}
+
+Vector<Resolution^>^
+Channel::resolutionList()
+{
+    return m_validResolutions;
+}
+
+/************************************************************
+ *                                                          *
+ *                         Resolution                       *
+ *                                                          *
+ ***********************************************************/
+
+Resolution::Resolution()
+{
+    m_size = ref new Size();
+    m_validRates = ref new Vector<Rate^>();
+}
+
+Resolution::Resolution(Video::Size^ size):
+    m_size(size)
+{ }
+
+String^
+Resolution::name()
+{
+   return size()->width().ToString() + "x" + size()->height().ToString();
+}
+
+Rate^
+Resolution::activeRate()
+{
+    return m_currentRate;
+}
+
+Vector<Rate^>^
+Resolution::rateList()
+{
+    return m_validRates;
+}
+
+Video::Size^
+Resolution::size()
+{
+    return m_size;
+}
+
+String^
+Resolution::format()
+{
+    return m_format;
+}
+
+void
+Resolution::setWidth(int width)
+{
+    m_size->setWidth(width);
+}
+
+void
+Resolution::setHeight(int height)
+{
+    m_size->setHeight(height);
+}
+
+void
+Resolution::setFormat(String^ format)
+{
+    m_format = format;
+}
+
+bool
+Resolution::setActiveRate(Rate^ rate)
+{
+   if (m_currentRate == rate)
+      return false;
+
+   m_currentRate = rate;
+   // set camera device rate here
+   return true;
+}
+
+/************************************************************
+ *                                                          *
+ *                         Device                           *
+ *                                                          *
+ ***********************************************************/
+
+Device::Device(String^ id)
+{
+    m_deviceId = id;
+    m_channels = ref new Vector<Channel^>();
+}
+
+String^
+Device::id()
+{
+    return m_deviceId;
+}
+
+Vector<Channel^>^
+Device::channelList()
+{
+   return m_channels;
+}
+
+String^
+Device::name()
+{
+    return m_name;
+}
+
+Channel^
+Device::channel()
+{
+    return m_currentChannel;
+}
+
+bool
+Device::setCurrentChannel(Channel^ channel)
+{
+    if (m_currentChannel == channel)
+        return false;
+    m_currentChannel = channel;
+    return true;
+}
+
+void
+Device::setName(String^ name)
+{
+    m_name = name;
+}
+
+void
+Device::save()
+{
+}
+
+bool
+Device::isActive()
+{
+    return false;
+   //return Video::DeviceModel::instance().activeDevice() == this;
+}
+
+void
+Device::SetDeviceProperties(String^ format, int width, int height, int rate)
+{
+    auto rl = m_currentChannel->resolutionList();
+    for (auto res : rl) {
+        if (res->format() == format &&
+            res->size()->width() == width &&
+            res->size()->height() == height &&
+            res->activeRate()->value() == rate)
+        {
+            m_currentChannel->setCurrentResolution(res);
+            WriteLine("SetDeviceProperties");
+            return;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Video.h b/Video.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad544d5ae1aadf0d9559791f96cd169dbc548cb0
--- /dev/null
+++ b/Video.h
@@ -0,0 +1,156 @@
+/**************************************************************************
+* Copyright (C) 2016 by Savoir-faire Linux                                *
+* Author: J�ger Nicolas <nicolas.jager@savoirfairelinux.com>              *
+* Author: Traczyk Andreas <andreas.traczyk@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, see <http://www.gnu.org/licenses/>.   *
+**************************************************************************/
+
+#pragma once
+
+using namespace Platform;
+
+namespace RingClientUWP
+{
+
+namespace Video
+{
+
+ref class Rate;
+ref class Resolution;
+ref class Device;
+
+public ref class Size sealed
+{
+internal:
+    unsigned int                width                   ();
+    unsigned int                height                  ();
+
+    void setWidth               ( unsigned int width    );
+    void setHeight              ( unsigned int height   );
+
+public:
+    Size() { };
+    Size(unsigned int w, unsigned int h):
+        m_Width(w),
+        m_Height(h) { };
+    Size(Size^ rhs):
+        m_Width(rhs->m_Width),
+        m_Height(rhs->m_Height) { };
+
+private:
+    unsigned int m_Width;
+    unsigned int m_Height;
+
+};
+
+public ref class Rate sealed
+{
+internal:
+    String^                     name            ();
+    unsigned int                value           ();
+
+    void setName                (   String^         name  );
+    void setValue               (   unsigned int    value );
+
+private:
+    String^                     m_name;
+    unsigned int                m_value;
+
+};
+
+public ref class Channel sealed
+{
+internal:
+    String^                     name                ();
+    Resolution^                 currentResolution   ();
+    Vector<Resolution^>^        resolutionList      ();
+
+    void setName                (   String^     name             );
+    void setCurrentResolution   (   Resolution^ currentResolution);
+
+public:
+    Channel();
+
+private:
+    String^                     m_name;
+    Resolution^                 m_currentResolution;
+    Vector<Resolution^>^        m_validResolutions;
+
+};
+
+public ref class Resolution sealed
+{
+internal:
+    String^                     name            ();
+    Rate^                       activeRate      ();
+    Vector<Rate^>^              rateList        ();
+    Size^                       size            ();
+    String^                     format          ();
+
+    bool setActiveRate          (   Rate^   rate    );
+    void setWidth               (   int     width   );
+    void setHeight              (   int     height  );
+    void setFormat              (   String^ format  );
+
+public:
+    Resolution();
+    Resolution(Size^ size);
+
+private:
+    Rate^                       m_currentRate;
+    Vector<Rate^>^              m_validRates;
+    Size^                       m_size;
+    String^                     m_format;
+
+};
+
+public ref class Device sealed
+{
+internal:
+    class PreferenceNames {
+    public:
+        constexpr static const char* RATE    = "rate"   ;
+        constexpr static const char* NAME    = "name"   ;
+        constexpr static const char* CHANNEL = "channel";
+        constexpr static const char* SIZE    = "size"   ;
+    };
+
+    Vector<Channel^>^           channelList     ();
+    String^                     id              ();
+    String^                     name            ();
+    Channel^                    channel         ();
+
+    bool setCurrentChannel      (   Channel^ channel    );
+    void setName                (   String^ name        );
+    
+
+public:
+    Device(String^ id);
+    void SetDeviceProperties(String^ format, int width, int height, int rate);
+
+    void save                   ();
+    bool isActive               ();
+
+private:
+    String^                     m_deviceId        ;
+    String^                     m_name            ;
+    Channel^                    m_currentChannel  ;
+    Vector<Channel^>^           m_channels        ;
+    bool                        m_requireSave     ;
+
+};
+
+} /* namespace Video */
+} /* namespace RingClientUWP */
\ No newline at end of file
diff --git a/VideoCaptureManager.cpp b/VideoCaptureManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b40be163bf38de8172d565f2a0a78ee986304670
--- /dev/null
+++ b/VideoCaptureManager.cpp
@@ -0,0 +1,411 @@
+/**************************************************************************
+* Copyright (C) 2016 by Savoir-faire Linux                                *
+* Author: J�ger Nicolas <nicolas.jager@savoirfairelinux.com>              *
+* Author: Traczyk Andreas <andreas.traczyk@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, see <http://www.gnu.org/licenses/>.   *
+**************************************************************************/
+#include "pch.h"
+
+#include "VideoCaptureManager.h"
+
+#include <MemoryBuffer.h>   // IMemoryBufferByteAccess
+
+using namespace RingClientUWP;
+using namespace Video;
+
+using namespace Windows::Graphics::Display;
+using namespace Windows::Graphics::Imaging;
+using namespace Windows::UI::Xaml::Media::Imaging;
+using namespace Windows::Media;
+using namespace Windows::Media::MediaProperties;
+using namespace Windows::Media::Capture;
+
+VideoCaptureManager::VideoCaptureManager():
+    mediaCapture(nullptr)
+    , isInitialized(false)
+    , isPreviewing_(false)
+    , isChangingCamera(false)
+    , isRendering(false)
+    , externalCamera(false)
+    , mirroringPreview(false)
+    , displayOrientation(DisplayOrientations::Portrait)
+    , displayRequest(ref new Windows::System::Display::DisplayRequest())
+    , RotationKey({ 0xC380465D, 0x2271, 0x428C,{ 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1 } })
+{
+    deviceList = ref new Vector<Device^>();
+    InitializeCopyFrameDispatcher();
+    captureTaskTokenSource = new cancellation_token_source();
+}
+
+Map<String^,String^>^
+VideoCaptureManager::getSettings(String^ device)
+{
+    return Utils::convertMap(DRing::getSettings(Utils::toString(device)));
+}
+
+void
+VideoCaptureManager::MediaCapture_Failed(Capture::MediaCapture^, Capture::MediaCaptureFailedEventArgs^ errorEventArgs)
+{
+    WriteLine("MediaCapture_Failed");
+    std::wstringstream ss;
+    ss << "MediaCapture_Failed: 0x" << errorEventArgs->Code << ": " << errorEventArgs->Message->Data();
+    WriteLine(ref new String(ss.str().c_str()));
+
+    if (captureTaskTokenSource)
+        captureTaskTokenSource->cancel();
+    CleanupCameraAsync();
+}
+
+task<void>
+VideoCaptureManager::CleanupCameraAsync()
+{
+    WriteLine("CleanupCameraAsync");
+
+    std::vector<task<void>> taskList;
+
+    if (isInitialized)
+    {
+        if (isPreviewing)
+        {
+            auto stopPreviewTask = create_task(StopPreviewAsync());
+            taskList.push_back(stopPreviewTask);
+        }
+
+        isInitialized = false;
+    }
+
+    return when_all(taskList.begin(), taskList.end())
+        .then([this]()
+    {
+        if (mediaCapture.Get() != nullptr)
+        {
+            mediaCapture->Failed -= mediaCaptureFailedEventToken;
+            mediaCapture = nullptr;
+        }
+    });
+}
+
+task<void>
+VideoCaptureManager::EnumerateWebcamsAsync()
+{
+    devInfoCollection = nullptr;
+
+    deviceList->Clear();
+
+    return create_task(DeviceInformation::FindAllAsync(DeviceClass::VideoCapture))
+        .then([this](task<DeviceInformationCollection^> findTask)
+    {
+        try {
+            devInfoCollection = findTask.get();
+            if (devInfoCollection == nullptr || devInfoCollection->Size == 0) {
+                WriteLine("No WebCams found.");
+            }
+            else {
+                for (unsigned int i = 0; i < devInfoCollection->Size; i++) {
+                    AddVideoDevice(i);
+                }
+                WriteLine("Enumerating Webcams completed successfully.");
+            }
+        }
+        catch (Platform::Exception^ e) {
+            WriteException(e);
+        }
+    });
+}
+
+task<void>
+VideoCaptureManager::StartPreviewAsync()
+{
+    WriteLine("StartPreviewAsync");
+    displayRequest->RequestActive();
+
+    auto sink = getSink();
+    sink->Source = mediaCapture.Get();
+
+    return create_task(mediaCapture->StartPreviewAsync())
+        .then([this](task<void> previewTask)
+    {
+        try {
+            previewTask.get();
+            isPreviewing = true;
+            startPreviewing();
+            WriteLine("StartPreviewAsync DONE");
+        }
+        catch (Exception ^e) {
+            WriteException(e);
+        }
+    });
+}
+
+task<void>
+VideoCaptureManager::StopPreviewAsync()
+{
+    WriteLine("StopPreviewAsync");
+
+    if (captureTaskTokenSource)
+        captureTaskTokenSource->cancel();
+
+    if (mediaCapture.Get()) {
+        return create_task(mediaCapture->StopPreviewAsync())
+            .then([this](task<void> stopTask)
+        {
+            try {
+                stopTask.get();
+                isPreviewing = false;
+                stopPreviewing();
+                displayRequest->RequestRelease();
+                WriteLine("StopPreviewAsync DONE");
+            }
+            catch (Exception ^e) {
+                WriteException(e);
+            }
+        });
+    }
+    else {
+        return create_task([](){});
+    }
+}
+
+task<void>
+VideoCaptureManager::InitializeCameraAsync()
+{
+    WriteLine("InitializeCameraAsync");
+
+    if (captureTaskTokenSource)
+        captureTaskTokenSource->cancel();
+
+    mediaCapture = ref new MediaCapture();
+
+    auto devInfo = devInfoCollection->GetAt(0); //preferences - video capture device
+
+    mediaCaptureFailedEventToken = mediaCapture->Failed +=
+        ref new Capture::MediaCaptureFailedEventHandler(this, &VideoCaptureManager::MediaCapture_Failed);
+
+    if (devInfo == nullptr)
+        return create_task([](){});
+
+    auto settings = ref new MediaCaptureInitializationSettings();
+    settings->VideoDeviceId = devInfo->Id;
+
+    return create_task(mediaCapture->InitializeAsync(settings))
+        .then([this](task<void> initTask)
+    {
+        try {
+            initTask.get();
+            SetCaptureSettings();
+            isInitialized = true;
+            WriteLine("InitializeCameraAsync DONE");
+            return StartPreviewAsync();
+        }
+        catch (Exception ^e) {
+            WriteException(e);
+            return create_task([](){});
+        }
+    });
+}
+
+void
+VideoCaptureManager::AddVideoDevice(uint8_t index)
+{
+    WriteLine("GetDeviceCaps " + index.ToString());
+    Platform::Agile<Windows::Media::Capture::MediaCapture^> mc;
+    mc = ref new MediaCapture();
+
+    auto devInfo = devInfoCollection->GetAt(index);
+
+    if (devInfo == nullptr)
+        return;
+
+    auto settings = ref new MediaCaptureInitializationSettings();
+    settings->VideoDeviceId = devInfo->Id;
+
+    create_task(mc->InitializeAsync(settings))
+        .then([=](task<void> initTask)
+    {
+        try {
+            initTask.get();
+            auto allprops = mc->VideoDeviceController->GetAvailableMediaStreamProperties(MediaStreamType::VideoPreview);
+            Video::Device^ device = ref new Device(devInfo->Id);
+            Video::Channel^ channel = ref new Channel();
+            for (auto props : allprops) {
+                MediaProperties::VideoEncodingProperties^ vidprops = static_cast<VideoEncodingProperties^>(props);
+                int width = vidprops->Width;
+                int height = vidprops->Height;
+                Video::Resolution^ resolution = ref new Resolution(ref new Size(width,height));
+                Video::Rate^ rate = ref new Rate();
+                unsigned int frame_rate = 0;
+                if (vidprops->FrameRate->Denominator != 0)
+                    frame_rate = vidprops->FrameRate->Numerator / vidprops->FrameRate->Denominator;
+                rate->setValue(frame_rate);
+                rate->setName(rate->value().ToString() + "fps");
+                resolution->setActiveRate(rate);
+                String^ format = vidprops->Subtype;
+                resolution->setFormat(format);
+                channel->resolutionList()->Append(resolution);
+                WriteLine(devInfo->Name + " "
+                    + width.ToString() + "x" + height.ToString()
+                    + " " + frame_rate.ToString() + "FPS" + " " + format);
+            }
+            device->channelList()->Append(channel);
+            device->setCurrentChannel(device->channelList()->GetAt(0));
+            auto location = devInfo->EnclosureLocation;
+            if (location != nullptr) {
+                if (location->Panel == Windows::Devices::Enumeration::Panel::Front) {
+                    device->setName(devInfo->Name + "-Front");
+                }
+                else if (location->Panel == Windows::Devices::Enumeration::Panel::Back) {
+                    device->setName(devInfo->Name + "-Back"); //ignore
+                }
+                else {
+                    device->setName(devInfo->Name);
+                }
+            }
+            else {
+                device->setName(devInfo->Name);
+            }
+            this->deviceList->Append(device);
+            this->activeDevice = deviceList->GetAt(0);
+            WriteLine("GetDeviceCaps DONE");
+            DRing::addVideoDevice(Utils::toString(device->name()));
+        }
+        catch (Platform::Exception^ e) {
+            WriteException(e);
+        }
+    });
+}
+
+void
+VideoCaptureManager::InitializeCopyFrameDispatcher()
+{
+    try {
+        TimeSpan timeSpan;
+        timeSpan.Duration = static_cast<long long>(1e7) / 30; // framerate
+
+        if (videoFrameCopyInvoker != nullptr)
+            delete(videoFrameCopyInvoker);
+
+        videoFrameCopyInvoker = ref new DispatcherTimer;
+        videoFrameCopyInvoker->Interval = timeSpan;
+        videoFrameCopyInvoker->Tick += ref new Windows::Foundation::EventHandler<Object^>(this, &VideoCaptureManager::CopyFrame);
+        isRendering = false;
+    }
+    catch (Exception^ e) {
+        WriteLine(e->ToString());
+    }
+}
+
+void
+VideoCaptureManager::CopyFrame(Object^ sender, Object^ e)
+{
+    if (!isRendering && isPreviewing) {
+        try {
+            create_task(VideoCaptureManager::CopyFrameAsync());
+        }
+        catch(Platform::COMException^ e) {
+            WriteLine(e->ToString());
+        }
+    }
+}
+
+task<void>
+VideoCaptureManager::CopyFrameAsync()
+{
+    auto previewProperties = static_cast<MediaProperties::VideoEncodingProperties^>(
+            mediaCapture->VideoDeviceController->GetMediaStreamProperties(Capture::MediaStreamType::VideoPreview));
+    unsigned int videoFrameWidth = previewProperties->Width;
+    unsigned int videoFrameHeight = previewProperties->Height;
+
+    auto videoFrame = ref new VideoFrame(BitmapPixelFormat::Bgra8, videoFrameWidth, videoFrameHeight);
+
+    try {
+        if (captureTaskTokenSource) {
+            delete captureTaskTokenSource;
+            captureTaskTokenSource = new cancellation_token_source();
+        }
+        return create_task(mediaCapture->GetPreviewFrameAsync(videoFrame), captureTaskTokenSource->get_token())
+            .then([this](VideoFrame^ currentFrame)
+        {
+            try {
+                isRendering = true;
+                auto bitmap = currentFrame->SoftwareBitmap;
+                if (bitmap->BitmapPixelFormat == BitmapPixelFormat::Bgra8) {
+                    const int BYTES_PER_PIXEL = 4;
+
+                    BitmapBuffer^ buffer = bitmap->LockBuffer(BitmapBufferAccessMode::ReadWrite);
+                    IMemoryBufferReference^ reference = buffer->CreateReference();
+
+                    Microsoft::WRL::ComPtr<IMemoryBufferByteAccess> byteAccess;
+                    if (SUCCEEDED(reinterpret_cast<IUnknown*>(reference)->QueryInterface(
+                        IID_PPV_ARGS(&byteAccess)))) {
+                        byte* data;
+                        unsigned capacity;
+                        byteAccess->GetBuffer(&data, &capacity);
+
+                        auto desc = buffer->GetPlaneDescription(0);
+
+                        byte* buf = (byte*)DRing::obtainFrame(capacity);
+
+                        if (buf) {
+                            for (int row = 0; row < desc.Height; row++) {
+                                for (int col = 0; col < desc.Width; col++) {
+                                    auto currPixel = desc.StartIndex + desc.Stride * row
+                                        + BYTES_PER_PIXEL * col;
+                                    buf[currPixel + 0] = data[currPixel + 0];
+                                    buf[currPixel + 1] = data[currPixel + 1];
+                                    buf[currPixel + 2] = data[currPixel + 2];
+                                }
+                            }
+                        }
+
+                        DRing::releaseFrame((void*)buf);
+                    }
+                    delete reference;
+                    delete buffer;
+                }
+                delete currentFrame;
+            }
+            catch (Exception^ e) {
+                WriteLine("failed to copy frame to bitmap");
+            }
+        }).then([=](task<void> previousTask) {
+            try {
+                previousTask.get();
+                isRendering = false;
+            }
+            catch (Platform::Exception^ e) {
+                WriteLine( "Caught exception from previous task.\n" );
+            }
+        });
+    }
+    catch(Exception^ e) {
+        WriteException(e);
+        throw std::exception();
+    }
+}
+
+void
+VideoCaptureManager::SetCaptureSettings()
+{
+    auto vp = ref new VideoEncodingProperties;
+    auto res = activeDevice->channel()->currentResolution();
+    vp->Width = res->size()->width();
+    vp->Height = res->size()->height();
+    vp->FrameRate->Numerator = res->activeRate()->value();
+    vp->FrameRate->Denominator = 1;
+    vp->Subtype = res->format();
+    auto encodingProperties = static_cast<IMediaEncodingProperties^>(vp);
+    create_task(mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(
+        MediaStreamType::VideoPreview, encodingProperties));
+}
\ No newline at end of file
diff --git a/VideoCaptureManager.h b/VideoCaptureManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..74ad03d78277e8ff1b552a02a50b0d549cf60146
--- /dev/null
+++ b/VideoCaptureManager.h
@@ -0,0 +1,103 @@
+/**************************************************************************
+* Copyright (C) 2016 by Savoir-faire Linux                                *
+* Author: J�ger Nicolas <nicolas.jager@savoirfairelinux.com>              *
+* Author: Traczyk Andreas <andreas.traczyk@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, see <http://www.gnu.org/licenses/>.   *
+**************************************************************************/
+#pragma once
+
+using namespace Windows::UI::Xaml;
+using namespace Windows::ApplicationModel::Core;
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::Media::Capture;
+using namespace Windows::Foundation;
+using namespace Concurrency;
+
+namespace RingClientUWP
+{
+
+delegate void StartPreviewing();
+delegate void StopPreviewing();
+delegate Windows::UI::Xaml::Controls::CaptureElement^ GetSink();
+
+namespace Video
+{
+
+public ref class VideoCaptureManager sealed
+{
+internal:
+    property bool isPreviewing
+    {
+        bool get() { return isPreviewing_; }
+        void set(bool value) { isPreviewing_ = value; }
+    }
+
+    Map<String^,String^>^ getSettings(String^ device);
+
+    VideoCaptureManager();
+
+    Windows::Graphics::Display::DisplayInformation^ displayInformation;
+    Windows::Graphics::Display::DisplayOrientations displayOrientation;
+
+    Windows::System::Display::DisplayRequest^ displayRequest;
+
+    const GUID RotationKey;
+
+    bool externalCamera;
+    bool mirroringPreview;
+    bool isInitialized;
+    bool isChangingCamera;
+    bool isRendering;
+
+    Vector<Device^>^ deviceList;
+    Device^ activeDevice;
+
+    DeviceInformationCollection^ devInfoCollection;
+
+    Platform::Agile<Windows::Media::Capture::MediaCapture^> mediaCapture;
+
+    task<void> InitializeCameraAsync();
+    task<void> StartPreviewAsync();
+    task<void> StopPreviewAsync();
+    task<void> EnumerateWebcamsAsync();
+    task<void> CleanupCameraAsync();
+
+    // event tokens
+    EventRegistrationToken mediaCaptureFailedEventToken;
+    EventRegistrationToken displayInformationEventToken;
+    EventRegistrationToken visibilityChangedEventToken;
+
+    cancellation_token_source* captureTaskTokenSource;
+
+    void MediaCapture_Failed(MediaCapture ^currentCaptureObject, MediaCaptureFailedEventArgs^ errorEventArgs);
+    void AddVideoDevice(uint8_t index);
+    void SetCaptureSettings();
+
+    DispatcherTimer^ videoFrameCopyInvoker;
+    task<void> CopyFrameAsync();
+    void CopyFrame(Object^ sender, Object^ e);
+    void InitializeCopyFrameDispatcher();
+
+    event StartPreviewing^ startPreviewing;
+    event StopPreviewing^ stopPreviewing;
+    event GetSink^ getSink;
+
+private:
+    bool isPreviewing_;
+
+};
+
+} /* namespace Video */
+} /* namespace RingClientUWP */
\ No newline at end of file
diff --git a/VideoManager.cpp b/VideoManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..86d973bb77ed7df2df48fb8d2ca0f6f5be746f1a
--- /dev/null
+++ b/VideoManager.cpp
@@ -0,0 +1,41 @@
+/**************************************************************************
+* Copyright (C) 2016 by Savoir-faire Linux                                *
+* Author: J�ger Nicolas <nicolas.jager@savoirfairelinux.com>              *
+* Author: Traczyk Andreas <andreas.traczyk@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, see <http://www.gnu.org/licenses/>.   *
+**************************************************************************/
+#include "pch.h"
+#include "VideoManager.h"
+
+using namespace RingClientUWP;
+using namespace Video;
+
+VideoManager::VideoManager()
+{
+    videoCaptureManager = ref new VideoCaptureManager();
+    videoRendererManager = ref new VideoRendererManager();
+}
+
+VideoCaptureManager^
+VideoManager::captureManager()
+{
+    return videoCaptureManager;
+}
+
+VideoRendererManager^
+VideoManager::rendererManager()
+{
+    return videoRendererManager;
+}
\ No newline at end of file
diff --git a/VideoManager.h b/VideoManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..de174b078cd8c1779279b4180a57037c4089dcf2
--- /dev/null
+++ b/VideoManager.h
@@ -0,0 +1,56 @@
+/**************************************************************************
+* Copyright (C) 2016 by Savoir-faire Linux                                *
+* Author: J�ger Nicolas <nicolas.jager@savoirfairelinux.com>              *
+* Author: Traczyk Andreas <andreas.traczyk@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, see <http://www.gnu.org/licenses/>.   *
+**************************************************************************/
+#pragma once
+
+namespace RingClientUWP
+{
+
+namespace Video
+{
+
+ref class VideoCaptureManager;
+ref class VideoRendererManager;
+
+public ref class VideoManager sealed
+{
+internal:
+    /* ref class singleton */
+    static property VideoManager^ instance
+    {
+        VideoManager^ get()
+        {
+            static VideoManager^ instance_ = ref new VideoManager();
+            return instance_;
+        }
+    }
+
+public:
+    VideoCaptureManager^    captureManager  ();
+    VideoRendererManager^   rendererManager ();
+
+private:
+    VideoManager();
+
+    VideoCaptureManager^    videoCaptureManager;
+    VideoRendererManager^   videoRendererManager;
+
+};
+
+} /* namespace Video */
+} /* namespace RingClientUWP */
\ No newline at end of file
diff --git a/VideoPage.xaml b/VideoPage.xaml
index d81d3f5ba9ea784ae16567d31f2c12f7fc2fdc07..57240faf6d16c726a4911b7519e096c7300c410b 100644
--- a/VideoPage.xaml
+++ b/VideoPage.xaml
@@ -137,19 +137,33 @@
                     <RowDefinition Height="*"/>
                     <RowDefinition x:Name="_rowChatBx_" Height="0"/>
                 </Grid.RowDefinitions>
-                <Grid Background="#000000"
-                      Grid.Row="0"
-                  PointerMoved="_videoControl__PointerMoved">
+                <Grid   Background="#000000"
+                        Grid.Row="0"
+                        PointerMoved="_videoControl__PointerMoved">
                     <StackPanel x:Name="_headerBar_"
-                            Background="{StaticResource SemiTransparentBlack}"
-                            HorizontalAlignment="Stretch"
-                            VerticalAlignment="Top"
-                            Height="50">
-                        <TextBlock x:Name="_callee_"
-                               Text="callee"
-                               Foreground="White"
-                               Margin="20,10"/>
+                                Background="{StaticResource SemiTransparentBlack}"
+                                HorizontalAlignment="Stretch"
+                                VerticalAlignment="Top"
+                                Height="50">
+                        <TextBlock  x:Name="_callee_"
+                                    Text="callee"
+                                    Foreground="White"
+                                    Margin="20,10"/>
                     </StackPanel>
+
+                    <!-- video -->
+                    <Image Name="IncomingVideoImage"
+                           Grid.Column="0"
+                           Canvas.ZIndex="-1"/>
+
+                    <!--camera preview-->
+                    <CaptureElement Name="PreviewImage"
+                                    Width="200"
+                                    VerticalAlignment="Center"
+                                    HorizontalAlignment="Right"
+                                    Stretch="Uniform"
+                                    Grid.Column="0"/>
+
                     <StackPanel x:Name="_controlsBar_"
                             HorizontalAlignment="Center"
                             VerticalAlignment="Bottom"
diff --git a/VideoPage.xaml.cpp b/VideoPage.xaml.cpp
index 112741cbd21289f7dbb36626b26bbe9fbfc1bd9c..ee44f937e1374efa74267b66b9afbe31fddbbbd6 100644
--- a/VideoPage.xaml.cpp
+++ b/VideoPage.xaml.cpp
@@ -20,8 +20,11 @@
 
 #include "VideoPage.xaml.h"
 
+#include <MemoryBuffer.h>   // IMemoryBufferByteAccess
+
 using namespace RingClientUWP::Views;
 using namespace ViewModel;
+using namespace Video;
 
 using namespace Concurrency;
 using namespace Platform;
@@ -39,19 +42,98 @@ using namespace Windows::Media::Capture;
 using namespace Windows::ApplicationModel::Core;
 using namespace Windows::UI::Core;
 
+using namespace Windows::Graphics::Display;
+using namespace Windows::Graphics::Imaging;
+using namespace Windows::Media;
+using namespace Windows::UI::Xaml::Media::Imaging;
+using namespace Windows::Media::Capture;
+using namespace Windows::Devices::Sensors;
+
 VideoPage::VideoPage()
 {
     InitializeComponent();
-}
 
-void
-RingClientUWP::Views::VideoPage::OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)
-{
+    VideoManager::instance->captureManager()->displayInformation = DisplayInformation::GetForCurrentView();
+    VideoManager::instance->captureManager()->EnumerateWebcamsAsync();
+
+    Page::NavigationCacheMode = Navigation::NavigationCacheMode::Required;
+
+    VideoManager::instance->rendererManager()->writeVideoFrame +=
+        ref new WriteVideoFrame([this](String^ id, uint8_t* buf, int width, int height)
+    {
+        CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
+        ref new DispatchedHandler([=]() {
+            try {
+                if (!VideoManager::instance->rendererManager()->renderers->Size)
+                    return;
+                VideoManager::instance->rendererManager()->renderer(id)->isRendering = true;
+                create_task(WriteFrameAsSoftwareBitmapAsync(id, buf, width, height))
+                    .then([=](task<void> previousTask) {
+                    try {
+                        previousTask.get();
+                    }
+                    catch (Platform::Exception^ e) {
+                        WriteLine( "Caught exception from previous task.\n" );
+                    }
+                });
+            }
+            catch(Platform::COMException^ e) {
+                WriteLine(e->ToString());
+            }
+        }));
+    });
+
+    VideoManager::instance->captureManager()->startPreviewing +=
+        ref new StartPreviewing([this]()
+    {
+        PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Visible;
+        PreviewImage->FlowDirection = VideoManager::instance->captureManager()->mirroringPreview ?
+            Windows::UI::Xaml::FlowDirection::RightToLeft :
+            Windows::UI::Xaml::FlowDirection::LeftToRight;
+    });
+
+    VideoManager::instance->captureManager()->stopPreviewing +=
+        ref new StopPreviewing([this]()
+    {
+        PreviewImage->Source = nullptr;
+        PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+    });
+
+    VideoManager::instance->captureManager()->getSink +=
+        ref new GetSink([this]()
+    {
+        return PreviewImage;
+    });
+
+    VideoManager::instance->rendererManager()->clearRenderTarget +=
+        ref new ClearRenderTarget([this]()
+    {
+        IncomingVideoImage->Source = nullptr;
+    });
+
+    RingD::instance->incomingAccountMessage +=
+        ref new IncomingAccountMessage([&](String^ accountId, String^ from, String^ payload)
+    {
+        scrollDown();
+    });
+
+    RingD::instance->stateChange +=
+        ref new StateChange([&](String^ callId, CallStatus state, int code)
+    {
+        if (state == CallStatus::ENDED) {
+            Video::VideoManager::instance->rendererManager()->raiseClearRenderTarget();
+        }
+    });
+
     RingD::instance->incomingAccountMessage += ref new IncomingAccountMessage([&](String^ accountId,
     String^ from, String^ payload) {
         scrollDown();
     });
+}
 
+void
+RingClientUWP::Views::VideoPage::OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)
+{
     updatePageContent();
 }
 
@@ -202,4 +284,54 @@ void RingClientUWP::Views::VideoPage::btnAny_entered(Platform::Object^ sender, W
 void RingClientUWP::Views::VideoPage::btnAny_exited(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e)
 {
     barFading_ = true;
-}
\ No newline at end of file
+}
+
+task<void>
+VideoPage::WriteFrameAsSoftwareBitmapAsync(String^ id, uint8_t* buf, int width, int height)
+{
+    auto vframe = ref new VideoFrame(BitmapPixelFormat::Bgra8, width, height);
+    auto frame = vframe->SoftwareBitmap;
+
+    const int BYTES_PER_PIXEL = 4;
+
+    BitmapBuffer^ buffer = frame->LockBuffer(BitmapBufferAccessMode::ReadWrite);
+    IMemoryBufferReference^ reference = buffer->CreateReference();
+
+    Microsoft::WRL::ComPtr<IMemoryBufferByteAccess> byteAccess;
+    if (SUCCEEDED(reinterpret_cast<IUnknown*>(reference)->QueryInterface(IID_PPV_ARGS(&byteAccess))))
+    {
+        byte* data;
+        unsigned capacity;
+        byteAccess->GetBuffer(&data, &capacity);
+
+        auto desc = buffer->GetPlaneDescription(0);
+
+        for (int row = 0; row < desc.Height; row++)
+        {
+            for (int col = 0; col < desc.Width; col++)
+            {
+                auto currPixel = desc.StartIndex + desc.Stride * row + BYTES_PER_PIXEL * col;
+
+                data[currPixel + 0] = buf[currPixel + 0];
+                data[currPixel + 1] = buf[currPixel + 1];
+                data[currPixel + 2] = buf[currPixel + 2];
+            }
+        }
+    }
+    delete reference;
+    delete buffer;
+
+    VideoManager::instance->rendererManager()->renderer(id)->isRendering = false;
+
+    auto sbSource = ref new Media::Imaging::SoftwareBitmapSource();
+    return create_task(sbSource->SetBitmapAsync(frame))
+        .then([this, sbSource]()
+    {
+        try {
+            IncomingVideoImage->Source = sbSource;
+        }
+        catch (Exception^ e) {
+            WriteException(e);
+        }
+    });
+}
diff --git a/VideoPage.xaml.h b/VideoPage.xaml.h
index 0f17ac0a844eebfc03149a2f9e42ce507f388ea8..d548f959d56bf488fe9690ac453930d7cf7cc07f 100644
--- a/VideoPage.xaml.h
+++ b/VideoPage.xaml.h
@@ -23,6 +23,11 @@
 using namespace Windows::Media::Capture;
 using namespace Windows::UI::Xaml::Navigation;
 
+using namespace Windows::UI::Xaml;
+using namespace Windows::ApplicationModel::Core;
+using namespace Windows::Devices::Enumeration;
+
+
 namespace RingClientUWP
 {
 /* delegate */
@@ -94,6 +99,8 @@ private:
     void _messageTextBox__KeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e);
     void sendMessage();
 
+    Concurrency::task<void> WriteFrameAsSoftwareBitmapAsync(String^ id, uint8_t* buf, int width, int height);
+
     void Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void _btnCancel__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void _btnHangUp__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e);
diff --git a/VideoRendererManager.cpp b/VideoRendererManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..84220a5cec4d0f8061ac20f490f14462028eddfd
--- /dev/null
+++ b/VideoRendererManager.cpp
@@ -0,0 +1,122 @@
+/**************************************************************************
+* Copyright (C) 2016 by Savoir-faire Linux                                *
+* Author: J�ger Nicolas <nicolas.jager@savoirfairelinux.com>              *
+* Author: Traczyk Andreas <andreas.traczyk@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, see <http://www.gnu.org/licenses/>.   *
+**************************************************************************/
+
+#include "pch.h"
+
+#include "VideoRendererManager.h"
+
+using namespace RingClientUWP;
+using namespace Video;
+
+using namespace Platform;
+
+using namespace Windows::UI::Core;
+using namespace Windows::ApplicationModel::Core;
+
+void
+VideoRenderer::bindSinkFunctions()
+{
+    using namespace std::placeholders;
+    target.pull = std::bind(&VideoRenderer::requestFrameBuffer,this, _1);
+    target.push = std::bind(&VideoRenderer::onNewFrame,this, _1);
+}
+
+DRing::SinkTarget::FrameBufferPtr
+VideoRenderer::requestFrameBuffer(std::size_t bytes)
+{
+    std::lock_guard<std::mutex> lk(video_mutex);
+    if (!daemonFramePtr_)
+        daemonFramePtr_.reset(new DRing::FrameBuffer);
+    daemonFramePtr_->storage.resize(bytes);
+    daemonFramePtr_->ptr = daemonFramePtr_->storage.data();
+    daemonFramePtr_->ptrSize = bytes;
+    return std::move(daemonFramePtr_);
+}
+
+void
+VideoRenderer::onNewFrame(DRing::SinkTarget::FrameBufferPtr buf)
+{
+    std::lock_guard<std::mutex> lk(video_mutex);
+    daemonFramePtr_ = std::move(buf);
+    auto id = Utils::toPlatformString(this->id);
+    VideoManager::instance->rendererManager()->raiseWriteVideoFrame(id);
+}
+
+VideoRendererManager::VideoRendererManager()
+{
+    renderers = ref new Map<String^, VideoRendererWrapper^>();
+}
+
+void
+VideoRendererManager::startedDecoding(String^ id, int width, int height)
+{
+    renderers->Insert(id, ref new VideoRendererWrapper());
+    auto renderer = renderers->Lookup(id)->renderer;
+    renderer->id = Utils::toString(id);
+    renderer->bindSinkFunctions();
+    renderer->width = width;
+    renderer->height = height;
+    MSG_(Utils::toString( "startedDecoding for sink id: " + id).c_str());
+    registerSinkTarget(id, renderer->target);
+}
+
+void
+VideoRendererManager::registerSinkTarget(String^ sinkID, const DRing::SinkTarget& target)
+{
+    MSG_(Utils::toString( "registerSinkTarget for sink id: " + sinkID).c_str());
+    DRing::registerSinkTarget(Utils::toString(sinkID), target);
+}
+
+void
+VideoRendererManager::raiseWriteVideoFrame(String^ id)
+{
+    auto renderer = renderers->Lookup(id)->renderer;
+    if (!renderer)
+        return;
+    writeVideoFrame(id,
+                    renderer->daemonFramePtr_->ptr,
+                    renderer->width,
+                    renderer->height);
+}
+
+void
+VideoRendererManager::raiseClearRenderTarget()
+{
+    clearRenderTarget();
+}
+
+void
+VideoRendererManager::removeRenderer(String^ id)
+{
+    if(!renderers)
+        return;
+    std::unique_lock<std::mutex> lk(renderers->Lookup(id)->render_mutex);
+    renderers->Lookup(id)->frame_cv.wait(lk, [=] {
+        return !renderers->Lookup(id)->isRendering;
+    });
+    renderers->Remove(id);
+}
+
+VideoRendererWrapper^
+VideoRendererManager::renderer(String^ id)
+{
+    if(!renderers)
+        return nullptr;
+    return renderers->Lookup(id);
+}
\ No newline at end of file
diff --git a/VideoRendererManager.h b/VideoRendererManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..24ba76b038da5e259c00c9cda8e239ccab72326c
--- /dev/null
+++ b/VideoRendererManager.h
@@ -0,0 +1,91 @@
+/**************************************************************************
+* Copyright (C) 2016 by Savoir-faire Linux                                *
+* Author: J�ger Nicolas <nicolas.jager@savoirfairelinux.com>              *
+* Author: Traczyk Andreas <andreas.traczyk@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, see <http://www.gnu.org/licenses/>.   *
+**************************************************************************/
+
+#pragma once
+
+#include "videomanager_interface.h"
+
+namespace RingClientUWP
+{
+
+delegate void WriteVideoFrame(String^, uint8_t*, int, int);
+delegate void ClearRenderTarget();
+
+namespace Video
+{
+
+class VideoRenderer
+{
+public:
+    std::string id;
+    std::mutex video_mutex;
+    DRing::SinkTarget target;
+    DRing::SinkTarget::FrameBufferPtr daemonFramePtr_;
+    int width;
+    int height;
+
+    void bindSinkFunctions();
+
+    DRing::SinkTarget::FrameBufferPtr requestFrameBuffer(std::size_t bytes);
+    void onNewFrame(DRing::SinkTarget::FrameBufferPtr buf);
+
+};
+
+ref class VideoRendererWrapper sealed
+{
+internal:
+    VideoRendererWrapper() {
+        renderer = std::make_shared<VideoRenderer>();
+        isRendering = false;
+    };
+
+    std::mutex render_mutex;
+    std::condition_variable frame_cv;
+
+    std::shared_ptr<VideoRenderer> renderer;
+    bool isRendering;
+};
+
+public ref class VideoRendererManager sealed
+{
+internal:
+    void startedDecoding(String^ id, int width, int height);
+    void registerSinkTarget(String^ sinkID, const DRing::SinkTarget& target);
+
+    /* events */
+    event WriteVideoFrame^ writeVideoFrame;
+    event ClearRenderTarget^ clearRenderTarget;
+
+    VideoRendererWrapper^ renderer(String^ id);
+    Map<String^,VideoRendererWrapper^>^ renderers;
+
+public:
+    VideoRendererManager();
+
+    void raiseWriteVideoFrame(String^ id);
+    void raiseClearRenderTarget();
+
+    void removeRenderer(String^ id);
+
+private:
+
+};
+
+} /* namespace Video */
+} /* namespace RingClientUWP */
\ No newline at end of file
diff --git a/WelcomePage.xaml.cpp b/WelcomePage.xaml.cpp
index 1a22547fbc35fedbdcb3b99aada487896ce93b89..f61275d15b3555ce08c99dd80839da8bfd17c410 100644
--- a/WelcomePage.xaml.cpp
+++ b/WelcomePage.xaml.cpp
@@ -33,8 +33,8 @@ void
 WelcomePage::PositionImage()
 {
     Rect imageBounds;
-    imageBounds.Width = _welcomePage_->ActualWidth;
-    imageBounds.Height = _welcomePage_->ActualWidth;
+    imageBounds.Width = static_cast<float>(_welcomePage_->ActualWidth);
+    imageBounds.Height = static_cast<float>(_welcomePage_->ActualHeight);
 
     _welcomeImage_->SetValue(Canvas::LeftProperty, imageBounds.Width * 0.5 - _welcomeImage_->Width * 0.5);
     _welcomeImage_->SetValue(Canvas::TopProperty, imageBounds.Height * 0.5 - _welcomeImage_->Height * 0.5);
diff --git a/pch.h b/pch.h
index 7e2d8256b2a2dbd06ebdc5f63447e9e49d72b7aa..7a002b4f5f9419dc47c34fbc2ce5df6c7cadf579 100644
--- a/pch.h
+++ b/pch.h
@@ -43,4 +43,10 @@
 #include "RingD.h"
 #include "RingDebug.h"
 #include "Utils.h"
-#include "UserPreferences.h"
\ No newline at end of file
+#include "UserPreferences.h"
+
+/* video headers */
+#include "Video.h"
+#include "VideoCaptureManager.h"
+#include "VideoManager.h"
+#include "VideoRendererManager.h"
\ No newline at end of file
diff --git a/ring-client-uwp.vcxproj b/ring-client-uwp.vcxproj
index 802976c2de7206c605d3c7c48657ae37a0ac7e9e..6f1281fa3bda30288882f3471956f0e15a58b50f 100644
--- a/ring-client-uwp.vcxproj
+++ b/ring-client-uwp.vcxproj
@@ -193,6 +193,10 @@
     <ClInclude Include="SmartPanelItemsViewModel.h" />
     <ClInclude Include="UserPreferences.h" />
     <ClInclude Include="Utils.h" />
+    <ClInclude Include="Video.h" />
+    <ClInclude Include="VideoCaptureManager.h" />
+    <ClInclude Include="VideoManager.h" />
+    <ClInclude Include="VideoRendererManager.h" />
     <ClInclude Include="VideoPage.xaml.h">
       <DependentUpon>VideoPage.xaml</DependentUpon>
     </ClInclude>
@@ -306,6 +310,10 @@
     <ClCompile Include="SmartPanelItem.cpp" />
     <ClCompile Include="SmartPanelItemsViewModel.cpp" />
     <ClCompile Include="UserPreferences.cpp" />
+    <ClCompile Include="Video.cpp" />
+    <ClCompile Include="VideoCaptureManager.cpp" />
+    <ClCompile Include="VideoManager.cpp" />
+    <ClCompile Include="VideoRendererManager.cpp" />
     <ClCompile Include="VideoPage.xaml.cpp">
       <DependentUpon>VideoPage.xaml</DependentUpon>
     </ClCompile>
diff --git a/ring-client-uwp.vcxproj.filters b/ring-client-uwp.vcxproj.filters
index 8e1641bd400508364ed420268fad1e6b7b157e4c..2d88f468ddc4c376179693b9bce9bb1c1f950eac 100644
--- a/ring-client-uwp.vcxproj.filters
+++ b/ring-client-uwp.vcxproj.filters
@@ -38,6 +38,15 @@
     <Filter Include="Controls">
       <UniqueIdentifier>{2cffcd5e-0546-4629-a152-37efd9c1128f}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Media">
+      <UniqueIdentifier>{bec54fb8-3a88-4687-8cbf-87325df1bcc7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Media\Video">
+      <UniqueIdentifier>{f711ca0c-c71f-47a7-9352-441ab4b44d5d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Media\Audio">
+      <UniqueIdentifier>{448e3594-0555-4c62-be25-71e1cebc80e1}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ApplicationDefinition Include="App.xaml" />
@@ -89,6 +98,18 @@
     <ClCompile Include="SmartPanelItemsViewModel.cpp">
       <Filter>ModelViews</Filter>
     </ClCompile>
+    <ClCompile Include="VideoManager.cpp">
+      <Filter>Media\Video</Filter>
+    </ClCompile>
+    <ClCompile Include="VideoRendererManager.cpp">
+      <Filter>Media\Video</Filter>
+    </ClCompile>
+    <ClCompile Include="Video.cpp">
+      <Filter>Media\Video</Filter>
+    </ClCompile>
+    <ClCompile Include="VideoCaptureManager.cpp">
+      <Filter>Media\Video</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="pch.h" />
@@ -140,6 +161,18 @@
     <ClInclude Include="SmartPanelItemsViewModel.h">
       <Filter>ModelViews</Filter>
     </ClInclude>
+    <ClInclude Include="VideoCaptureManager.h">
+      <Filter>Media\Video</Filter>
+    </ClInclude>
+    <ClInclude Include="VideoManager.h">
+      <Filter>Media\Video</Filter>
+    </ClInclude>
+    <ClInclude Include="VideoRendererManager.h">
+      <Filter>Media\Video</Filter>
+    </ClInclude>
+    <ClInclude Include="Video.h">
+      <Filter>Media\Video</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Image Include="Assets\LockScreenLogo.scale-200.png">