diff --git a/CMakeLists.txt b/CMakeLists.txt
index ca9ee58cc704a54bb6379df9dfff96494e846375..a77b3c1438aa9f356f27c426004ae98fca6f9ba4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,6 +37,8 @@ FIND_PACKAGE(OpenGL REQUIRED)
 EXECUTE_PROCESS(COMMAND git submodule update --init
                 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
 
+get_filename_component(PARENT_DIR ${CMAKE_SOURCE_DIR} PATH)
+
 INCLUDE(ExternalProject)
 ExternalProject_Add(libqrencode
     GIT_SUBMODULES libqrencode
@@ -52,6 +54,17 @@ ExternalProject_Add(libqrencode
 
 INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/libqrencode/include)
 LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/libqrencode/lib)
+INCLUDE_DIRECTORIES(${PARENT_DIR}/daemon/contrib/native/ffmpeg)
+
+set(SHADERS_FILE "Shader.metallib")
+add_custom_command (OUTPUT ${CMAKE_SOURCE_DIR}/Shader.metallib
+                    COMMAND ${CMAKE_SOURCE_DIR}/generateShaderLib.sh
+                    COMMENT "Creating Shader.metallib")
+
+                    add_custom_target(
+    shader ALL
+    DEPENDS ${CMAKE_SOURCE_DIR}/Shader.metallib
+    )
 
 IF(NOT (${ENABLE_SPARKLE} MATCHES false))
    MESSAGE("Sparkle auto-update enabled")
@@ -212,6 +225,8 @@ SET(ringclient_VIEWS
    src/views/HoverButton.mm
    src/views/CenteredClipView.h
    src/views/CenteredClipView.mm
+   src/views/CallMTKView.h
+   src/views/CallMTKView.mm
 )
 
 SET(ringclient_OTHERS
@@ -229,8 +244,9 @@ SET(ringclient_OTHERS
    src/NSString+Extensions.h
    src/NSString+Extensions.mm
    src/RingMainWindow.h
-   src/RingMainWindow.mm)
-
+   src/RingMainWindow.mm
+   src/Shader.metal
+)
 
 SET(ringclient_XIBS
    MainMenu
@@ -323,6 +339,8 @@ SET_SOURCE_FILES_PROPERTIES(${ring_ICONS} PROPERTIES
        MACOSX_PACKAGE_LOCATION Resources)
 SET_SOURCE_FILES_PROPERTIES(Credits.rtf PROPERTIES
        MACOSX_PACKAGE_LOCATION Resources)
+SET_SOURCE_FILES_PROPERTIES(Shader.metallib PROPERTIES
+       MACOSX_PACKAGE_LOCATION Resources)
 
 # package ringtones
 IF(NOT IS_DIRECTORY ${RINGTONE_DIR})
@@ -405,6 +423,7 @@ SET(TO_ADD
    ${LOCALIZABLE_FILES}
    ${myApp_ICON}
    Credits.rtf
+   Shader.metallib
    ${ring_ICONS}
    ${ring_RINGTONES})
 
@@ -438,6 +457,8 @@ TARGET_LINK_LIBRARIES( ${PROJ_NAME}
    -lqrencode
 )
 
+target_link_libraries(${PROJ_NAME} ${PARENT_DIR}/daemon/contrib/x86_64-apple-darwin${CMAKE_SYSTEM_VERSION}/lib/libavutil.a)
+
 IF(ENABLE_SPARKLE)
    TARGET_LINK_LIBRARIES(${PROJ_NAME} ${SPARKLE_FRAMEWORK})
 ENDIF(ENABLE_SPARKLE)
@@ -448,6 +469,8 @@ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Quartz")
 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AVFoundation")
 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AddressBook")
 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework SystemConfiguration")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework MetalKit")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Metal")
 
 # These variables are specific to our plist and are NOT standard CMake variables
 SET(MACOSX_BUNDLE_NSMAIN_NIB_FILE "MainMenu")
diff --git a/generateShaderLib.sh b/generateShaderLib.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4294d74fac04684c5927fa63f3739019c830c2ea
--- /dev/null
+++ b/generateShaderLib.sh
@@ -0,0 +1,2 @@
+xcrun -sdk macosx metal -c ../src/Shader.metal -o ../Shader.air
+xcrun -sdk macosx metallib ../Shader.air -o ../Shader.metallib
diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm
index a08f77c01dfb035d8b7ae86a74da89009efe3156..6ad839e20168985f0942a0231ff8d8da4857b2a7 100644
--- a/src/CurrentCallVC.mm
+++ b/src/CurrentCallVC.mm
@@ -17,6 +17,10 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
  */
 #import "CurrentCallVC.h"
+extern "C" {
+#import "libavutil/frame.h"
+#import "libavutil/display.h"
+}
 
 #import <QuartzCore/QuartzCore.h>
 
@@ -41,8 +45,8 @@
 #import "delegates/ImageManipulationDelegate.h"
 #import "ChatVC.h"
 #import "views/IconButton.h"
-#import "views/CallLayer.h"
 #import "utils.h"
+#import "views/CallMTKView.h"
 
 @interface RendererConnectionsHolder : NSObject
 
@@ -120,7 +124,9 @@
 
 // Video
 @property (unsafe_unretained) IBOutlet CallView *videoView;
-@property (unsafe_unretained) IBOutlet NSView *previewView;
+@property (unsafe_unretained) IBOutlet CallMTKView *previewView;
+
+@property (unsafe_unretained) IBOutlet CallMTKView *videoMTKView;
 
 @property RendererConnectionsHolder* previewHolder;
 @property RendererConnectionsHolder* videoHolder;
@@ -129,6 +135,7 @@
 @property QMetaObject::Connection messageConnection;
 @property QMetaObject::Connection mediaAddedConnection;
 @property QMetaObject::Connection profileUpdatedConnection;
+@property NSImageView *testView;
 
 @end
 
@@ -142,6 +149,10 @@
 
 @synthesize previewHolder;
 @synthesize videoHolder;
+CVPixelBufferPoolRef pixelBufferPoolDistantView;
+CVPixelBufferRef pixelBufferDistantView;
+CVPixelBufferPoolRef pixelBufferPoolPreview;
+CVPixelBufferRef pixelBufferPreview;
 
 -(void) setCurrentCall:(const std::string&)callUid
           conversation:(const std::string&)convUid
@@ -167,35 +178,9 @@
     videoView.callId = callUid;
 }
 
-- (void) ensureLayoutForCallStatus:(lrc::api::call::Status) status {
-    using Status = lrc::api::call::Status;
-    switch (status) {
-        case Status::IN_PROGRESS:
-            if (![videoView.layer isKindOfClass:[CallLayer class]]) {
-                [videoView setLayer:[[CallLayer alloc] init]];
-            }
-            break;
-        default:
-            if ([videoView.layer isKindOfClass:[CallLayer class]]) {
-                [videoView setLayer:[CALayer layer]];
-                [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
-            }
-            break;
-    }
-    holdOnOffButton.image = status == lrc::api::call::Status::PAUSED ?
-    [NSImage imageNamed:@"ic_action_holdoff.png"] : [NSImage imageNamed:@"ic_action_hold.png"];
-}
-
 - (void)awakeFromNib
 {
-    NSLog(@"INIT CurrentCall VC");
     [self.view setWantsLayer:YES];
-
-    [previewView setWantsLayer:YES];
-    [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
-    [previewView.layer setContentsGravity:kCAGravityResizeAspectFill];
-    [previewView.layer setFrame:previewView.frame];
-
     [controlsPanel setWantsLayer:YES];
     [controlsPanel.layer setBackgroundColor:[NSColor clearColor].CGColor];
     [controlsPanel.layer setFrame:controlsPanel.frame];
@@ -294,7 +279,8 @@
     [self setBackground];
 
     using Status = lrc::api::call::Status;
-    [self ensureLayoutForCallStatus:currentCall.status];
+    holdOnOffButton.image = currentCall.status == lrc::api::call::Status::PAUSED ?
+    [NSImage imageNamed:@"ic_action_holdoff.png"] : [NSImage imageNamed:@"ic_action_hold.png"];
     switch (currentCall.status) {
         case Status::SEARCHING:
         case Status::CONNECTING:
@@ -321,9 +307,29 @@
             [self setupConference:currentCall];
             break;*/
         case Status::PAUSED:
+            [self.videoMTKView fillWithBlack];
+            [self.previewView fillWithBlack];
+            [bluerBackgroundEffect setHidden:NO];
+            [backgroundImage setHidden:NO];
+            [self.previewView setHidden: YES];
+            [self.videoMTKView setHidden: YES];
+            self.previewView.stopRendering = true;
+            self.videoMTKView.stopRendering = true;
+            break;
         case Status::INACTIVE:
+            if(currentCall.isAudioOnly) {
+                [self setUpAudioOnlyView];
+            } else {
+                [self setUpVideoCallView];
+            }
+            break;
         case Status::IN_PROGRESS:
-            // change constraints (uncollapse avatar)
+            self.previewView.stopRendering = false;
+            self.videoMTKView.stopRendering = false;
+            [previewView fillWithBlack];
+            [self.videoMTKView fillWithBlack];
+            [self.previewView setHidden: NO];
+            [self.videoMTKView setHidden: NO];
             if(currentCall.isAudioOnly) {
                 [self setUpAudioOnlyView];
             } else {
@@ -345,13 +351,17 @@
     [outgoingPhoto setHidden:YES];
     [headerContainer setHidden:NO];
     [previewView setHidden: NO];
+    [self.videoMTKView setHidden:NO];
     [bluerBackgroundEffect setHidden:YES];
     [backgroundImage setHidden:YES];
+    [audioCallView setHidden:YES];
 }
 
 -(void) setUpAudioOnlyView {
     [audioCallView setHidden:NO];
     [headerContainer setHidden:YES];
+    [self.previewView setHidden: YES];
+    [self.videoMTKView setHidden: YES];
     [audioCallPhoto setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
 }
 
@@ -397,7 +407,6 @@
     return [[NSImage alloc] initWithData:imageData];
 }
 
-
 -(void) setupContactInfo:(NSImageView*)imageView
 {
     [imageView setImage: [self getContactImageOfSize:120.0 withDefaultAvatar:YES]];
@@ -426,7 +435,6 @@
     }
 }
 
-
 -(void) setupConference:(Call*) c
 {
     [videoView setShouldAcceptInteractions:YES];
@@ -472,8 +480,8 @@
     self.videoStarted = QObject::connect(callModel,
                                          &lrc::api::NewCallModel::remotePreviewStarted,
                                          [self](const std::string& callId, Video::Renderer* renderer) {
-                                             [videoView setLayer:[[CallLayer alloc] init]];
                                              [videoView setShouldAcceptInteractions:YES];
+                                             [self.videoMTKView setHidden:NO];
                                              [self mouseIsMoving: NO];
                                              [self connectVideoRenderer:renderer];
                                          });
@@ -481,11 +489,11 @@
     if (callModel->hasCall(callUid_)) {
         if (auto renderer = callModel->getRenderer(callUid_)) {
             QObject::disconnect(self.videoStarted);
+            [self.videoMTKView setHidden:NO];
             [self connectVideoRenderer: renderer];
         }
     }
     [self connectPreviewRenderer];
-
 }
 
 -(void) connectPreviewRenderer
@@ -493,31 +501,42 @@
     QObject::disconnect(previewHolder.frameUpdated);
     QObject::disconnect(previewHolder.stopped);
     QObject::disconnect(previewHolder.started);
-    previewHolder.started = QObject::connect(&Video::PreviewManager::instance(),
+    previewHolder.started =
+    QObject::connect(&Video::PreviewManager::instance(),
                      &Video::PreviewManager::previewStarted,
                      [=](Video::Renderer* renderer) {
+                         [self.previewView setHidden:NO];
+                         self.previewView.stopRendering = false;
                          QObject::disconnect(previewHolder.frameUpdated);
-                         previewHolder.frameUpdated = QObject::connect(renderer,
-                                                                       &Video::Renderer::frameUpdated,
-                                                                       [=]() {
-                                                                           [self renderer:Video::PreviewManager::instance().previewRenderer()
-                                                                       renderFrameForPreviewView:previewView];
-                                                                       });
-                     });
-
+                         previewHolder.frameUpdated =
+                         QObject::connect(renderer,
+                                          &Video::Renderer::frameUpdated,
+                                          [=]() {
+                                              if(!renderer->isRendering()) {
+                                                  return;
+                                              }
+                                              [self renderer:renderer renderFrameForPreviewView: self.previewView];
+                         });
+    });
     previewHolder.stopped = QObject::connect(&Video::PreviewManager::instance(),
                      &Video::PreviewManager::previewStopped,
                      [=](Video::Renderer* renderer) {
                         QObject::disconnect(previewHolder.frameUpdated);
-                        [previewView.layer setContents:nil];
+                        [self.previewView setHidden:YES];
+                        self.previewView.stopRendering = true;
                      });
 
-    previewHolder.frameUpdated = QObject::connect(Video::PreviewManager::instance().previewRenderer(),
-                                                 &Video::Renderer::frameUpdated,
-                                                 [=]() {
-                                                     [self renderer:Video::PreviewManager::instance().previewRenderer()
-                                                            renderFrameForPreviewView:previewView];
-                                                 });
+    previewHolder.frameUpdated =
+    QObject::connect(Video::PreviewManager::instance().previewRenderer(),
+                     &Video::Renderer::frameUpdated,
+                     [=]() {
+                         if(!Video::PreviewManager::instance()
+                            .previewRenderer()->isRendering()) {
+                             return;
+                         }
+                         [self renderer:Video::PreviewManager::instance()
+                          .previewRenderer() renderFrameForPreviewView: self.previewView];
+    });
 }
 
 -(void) connectVideoRenderer: (Video::Renderer*)renderer
@@ -535,80 +554,222 @@
                          if(!renderer->isRendering()) {
                              return;
                          }
-                         [self renderer:renderer renderFrameForDistantView:videoView];
+                         [self renderer:renderer renderFrameForDistantView:self.videoMTKView];
                      });
 
-    videoHolder.started = QObject::connect(renderer,
+    videoHolder.started =
+    QObject::connect(renderer,
                      &Video::Renderer::started,
                      [=]() {
-                         if (![videoView.layer isKindOfClass:[CallLayer class]]) {
-                             [videoView setLayer:[[CallLayer alloc] init]];
-                         }
                          [self mouseIsMoving: NO];
+                         self.videoMTKView.stopRendering = false;
+                         [self.videoMTKView setHidden:NO];
+                         [bluerBackgroundEffect setHidden:YES];
+                         [backgroundImage setHidden:YES];
                          [videoView setShouldAcceptInteractions:YES];
                          QObject::disconnect(videoHolder.frameUpdated);
-                         videoHolder.frameUpdated = QObject::connect(renderer,
-                                                                     &Video::Renderer::frameUpdated,
-                                                                     [=]() {
-                                                                         [self renderer:renderer renderFrameForDistantView:videoView];
-                                                                     });
+                         videoHolder.frameUpdated
+                         = QObject::connect(renderer,
+                                            &Video::Renderer::frameUpdated,
+                                            [=]() {
+                                                if(!renderer->isRendering()) {
+                                                    return;
+                                                }
+                                                [self renderer:renderer renderFrameForDistantView:self.videoMTKView];
+                                            });
                      });
 
     videoHolder.stopped = QObject::connect(renderer,
                      &Video::Renderer::stopped,
                      [=]() {
-                         [(CallLayer*)videoView.layer setVideoRunning:NO];
-                         [videoView setLayer:[CALayer layer]];
-                         [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
                          [self mouseIsMoving: YES];
+                         self.videoMTKView.stopRendering = true;
+                         [self.videoMTKView setHidden:YES];
+                         [bluerBackgroundEffect setHidden:NO];
+                         [backgroundImage setHidden:NO];
                          [videoView setShouldAcceptInteractions:NO];
                          QObject::disconnect(videoHolder.frameUpdated);
                      });
 }
 
--(void) renderer: (Video::Renderer*)renderer renderFrameForPreviewView:(NSView*) view
+-(void) renderer: (Video::Renderer*)renderer renderFrameForPreviewView:(CallMTKView*) view
 {
-    QSize res = renderer->size();
-
-    auto frame_ptr = renderer->currentFrame();
-    auto frame_data = frame_ptr.ptr;
-    if (!frame_data)
-        return;
-
-    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
-    CGContextRef newContext = CGBitmapContextCreate(frame_data,
-                                                    res.width(),
-                                                    res.height(),
-                                                    8,
-                                                    4*res.width(),
-                                                    colorSpace,
-                                                    kCGImageAlphaPremultipliedLast);
-
-
-    CGImageRef newImage = CGBitmapContextCreateImage(newContext);
-
-    /*We release some components*/
-    CGContextRelease(newContext);
-    CGColorSpaceRelease(colorSpace);
-
-    [CATransaction begin];
-    view.layer.contents = (__bridge id)newImage;
-    [CATransaction commit];
-
-    CFRelease(newImage);
+    @autoreleasepool {
+        auto framePtr = renderer->currentAVFrame();
+        auto frame = framePtr.get();
+        if(!frame || !frame->width || !frame->height) {
+            return;
+        }
+        auto frameSize = CGSizeMake(frame->width, frame->height);
+        auto rotation = 0;
+        if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
+            [view renderWithPixelBuffer:(CVPixelBufferRef)frame->data[3]
+                                   size: frameSize
+                               rotation: rotation
+                              fillFrame: true];
+            return;
+        }
+        else if (CVPixelBufferRef pixelBuffer = [self getBufferForPreviewFromFrame:frame]) {
+            [view renderWithPixelBuffer: pixelBuffer
+                                   size: frameSize
+                               rotation: rotation
+                              fillFrame: true];
+        }
+    }
 }
 
--(void) renderer: (Video::Renderer*)renderer renderFrameForDistantView:(CallView*) view
+-(void) renderer: (Video::Renderer*)renderer renderFrameForDistantView:(CallMTKView*) view
 {
-    auto frame_ptr = renderer->currentFrame();
-    if (!frame_ptr.ptr)
-        return;
+    @autoreleasepool {
+        auto framePtr = renderer->currentAVFrame();
+        auto frame = framePtr.get();
+        if(!frame || !frame->width || !frame->height)  {
+            return;
+        }
+        auto frameSize = CGSizeMake(frame->width, frame->height);
+        auto rotation = 0;
+        if (auto matrix = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
+            const int32_t* data = reinterpret_cast<int32_t*>(matrix->data);
+            rotation = av_display_rotation_get(data);
+        }
+        if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
+            [view renderWithPixelBuffer: (CVPixelBufferRef)frame->data[3]
+                                   size: frameSize
+                               rotation: rotation
+                              fillFrame: false];
+        }
+        if (CVPixelBufferRef pixelBuffer = [self getBufferForDistantViewFromFrame:frame]) {
+            [view renderWithPixelBuffer: pixelBuffer
+                                   size: frameSize
+                               rotation: rotation
+                              fillFrame: false];
+        }
+    }
+}
+
+-(CVPixelBufferRef) getBufferForPreviewFromFrame:(const AVFrame*)frame {
+    if(!frame || !frame->data[0] || !frame->data[1]) {
+        return nil;
+    }
+    CVReturn theError;
+    bool createPool = false;
+    if (!pixelBufferPoolPreview) {
+        createPool = true;
+    } else {
+        NSDictionary* atributes = (__bridge NSDictionary*)CVPixelBufferPoolGetAttributes(pixelBufferPoolPreview);
+        int width = [[atributes objectForKey:(NSString*)kCVPixelBufferWidthKey] intValue];
+        int height = [[atributes objectForKey:(NSString*)kCVPixelBufferHeightKey] intValue];
+        if (width != frame->width || height != frame->height) {
+            createPool = true;
+        }
+    }
+    if (createPool) {
+        CVPixelBufferPoolRelease(pixelBufferPoolPreview);
+        CVPixelBufferRelease(pixelBufferPreview);
+        pixelBufferPreview = nil;
+        pixelBufferPoolPreview = nil;
+        NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
+        [attributes setObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
+        [attributes setObject:[NSNumber numberWithInt:frame->width] forKey: (NSString*)kCVPixelBufferWidthKey];
+        [attributes setObject:[NSNumber numberWithInt:frame->height] forKey: (NSString*)kCVPixelBufferHeightKey];
+        [attributes setObject:@(frame->linesize[0]) forKey:(NSString*)kCVPixelBufferBytesPerRowAlignmentKey];
+        [attributes setObject:[NSDictionary dictionary] forKey:(NSString*)kCVPixelBufferIOSurfacePropertiesKey];
+        theError = CVPixelBufferPoolCreate(kCFAllocatorDefault, NULL, (__bridge CFDictionaryRef) attributes, &pixelBufferPoolPreview);
+        if (theError != kCVReturnSuccess) {
+            NSLog(@"CVPixelBufferPoolCreate Failed");
+            return nil;
+        }
+    }
+    if(!pixelBufferPreview) {
+        theError = CVPixelBufferPoolCreatePixelBuffer(NULL, pixelBufferPoolPreview, &pixelBufferPreview);
+        if(theError != kCVReturnSuccess) {
+            NSLog(@"CVPixelBufferPoolCreatePixelBuffer Failed");
+            return nil;
+        }
+    }
+    theError = CVPixelBufferLockBaseAddress(pixelBufferPreview, 0);
+    if (theError != kCVReturnSuccess) {
+        NSLog(@"lock error");
+        return nil;
+    }
+    size_t bytePerRowY = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferPreview, 0);
+    size_t bytesPerRowUV = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferPreview, 1);
+    void* base = CVPixelBufferGetBaseAddressOfPlane(pixelBufferPreview, 0);
+    memcpy(base, frame->data[0], bytePerRowY * frame->height);
+    base = CVPixelBufferGetBaseAddressOfPlane(pixelBufferPreview, 1);
+    memcpy(base, frame->data[1], bytesPerRowUV * frame->height/2);
+    CVPixelBufferUnlockBaseAddress(pixelBufferPreview, 0);
+    return pixelBufferPreview;
+}
 
-    CallLayer* callLayer = (CallLayer*) view.layer;
-    if ([callLayer respondsToSelector:@selector(setCurrentFrame:)]) {
-        [callLayer setCurrentFrame:std::move(frame_ptr)];
-        [callLayer setVideoRunning:YES];
+-(CVPixelBufferRef) getBufferForDistantViewFromFrame:(const AVFrame*)frame {
+    if(!frame || !frame->data[0] || !frame->data[1]) {
+        return nil;
+    }
+    CVReturn theError;
+    bool createPool = false;
+    if (!pixelBufferPoolDistantView){
+        createPool = true;
+    }
+    NSDictionary* atributes = (__bridge NSDictionary*)CVPixelBufferPoolGetPixelBufferAttributes(pixelBufferPoolDistantView);
+    int width = [[atributes objectForKey:(NSString*)kCVPixelBufferWidthKey] intValue];
+    int height = [[atributes objectForKey:(NSString*)kCVPixelBufferHeightKey] intValue];
+    if (width != frame->width || height != frame->height) {
+        createPool = true;
     }
+    if (createPool) {
+        CVPixelBufferPoolRelease(pixelBufferPoolDistantView);
+        CVPixelBufferRelease(pixelBufferDistantView);
+        pixelBufferDistantView = nil;
+        pixelBufferPoolDistantView = nil;
+        NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
+        [attributes setObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
+        [attributes setObject:[NSNumber numberWithInt:frame->width] forKey: (NSString*)kCVPixelBufferWidthKey];
+        [attributes setObject:[NSNumber numberWithInt:frame->height] forKey: (NSString*)kCVPixelBufferHeightKey];
+        [attributes setObject:@(frame->linesize[0]) forKey:(NSString*)kCVPixelBufferBytesPerRowAlignmentKey];
+        [attributes setObject:[NSDictionary dictionary] forKey:(NSString*)kCVPixelBufferIOSurfacePropertiesKey];
+        theError = CVPixelBufferPoolCreate(kCFAllocatorDefault, NULL, (__bridge CFDictionaryRef) attributes, &pixelBufferPoolDistantView);
+        if (theError != kCVReturnSuccess) {
+            return nil;
+            NSLog(@"CVPixelBufferPoolCreate Failed");
+        }
+    }
+    if(!pixelBufferDistantView) {
+        theError = CVPixelBufferPoolCreatePixelBuffer(NULL, pixelBufferPoolDistantView, &pixelBufferDistantView);
+        if(theError != kCVReturnSuccess) {
+            return nil;
+            NSLog(@"CVPixelBufferPoolCreatePixelBuffer Failed");
+        }
+    }
+    theError = CVPixelBufferLockBaseAddress(pixelBufferDistantView, 0);
+    if (theError != kCVReturnSuccess) {
+        return nil;
+        NSLog(@"lock error");
+    }
+    size_t bytePerRowY = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferDistantView, 0);
+    size_t bytesPerRowUV = CVPixelBufferGetBytesPerRowOfPlane(pixelBufferDistantView, 1);
+    void* base = CVPixelBufferGetBaseAddressOfPlane(pixelBufferDistantView, 0);
+    memcpy(base, frame->data[0], bytePerRowY * frame->height);
+    base = CVPixelBufferGetBaseAddressOfPlane(pixelBufferDistantView, 1);
+    uint32_t size = frame->linesize[1] * frame->height / 2;
+    uint8_t* dstData = new uint8_t[2 * size];
+    uint8_t * firstData = new uint8_t[size];
+    memcpy(firstData, frame->data[1], size);
+    uint8_t * secondData  = new uint8_t[size];
+    memcpy(secondData, frame->data[2], size);
+    for (int i = 0; i < 2 * size; i++){
+        if (i % 2 == 0){
+            dstData[i] = firstData[i/2];
+        }else {
+            dstData[i] = secondData[i/2];
+        }
+    }
+    memcpy(base, dstData, bytesPerRowUV * frame->height/2);
+    CVPixelBufferUnlockBaseAddress(pixelBufferDistantView, 0);
+    free(dstData);
+    free(firstData);
+    free(secondData);
+    return pixelBufferDistantView;
 }
 
 - (void) initFrame
@@ -617,6 +778,8 @@
     [self.view setHidden:YES];
     self.view.layer.position = self.view.frame.origin;
     [self collapseRightView];
+    self.testView = [[NSImageView alloc] initWithFrame:self.view.frame];
+    [self.view addSubview:self.testView];
 }
 
 # pragma private IN/OUT animations
@@ -653,10 +816,6 @@
     QObject::disconnect(previewHolder.stopped);
     QObject::disconnect(previewHolder.started);
     QObject::disconnect(self.messageConnection);
-    [previewView.layer setContents:nil];
-    [previewView setHidden: YES];
-    [videoView setLayer:[CALayer layer]];
-    [videoView.layer setBackgroundColor:[[NSColor blackColor] CGColor]];
 
     [self.chatButton setHidden:YES];
     [self.chatButton setPressed:NO];
@@ -677,6 +836,8 @@
     //outgoing view
     [outgoingPersonLabel setStringValue:@""];
     [outgoingStateLabel setStringValue:@""];
+    [self.previewView setHidden:YES];
+    [self.videoMTKView setHidden:YES];
 }
 
 -(void) setupCallView
@@ -815,7 +976,6 @@
         return;
 
     auto* callModel = accountInfo_->callModel.get();
-
     callModel->hangUp(callUid_);
 }
 
diff --git a/src/RingWindowController.mm b/src/RingWindowController.mm
index 3fde23cb522d43b06f734edfc6764bea0ae1366e..f23969c5f1846825f698d1c8571434b9f954ed4b 100644
--- a/src/RingWindowController.mm
+++ b/src/RingWindowController.mm
@@ -37,6 +37,7 @@
 #import <api/contact.h>
 #import <api/datatransfermodel.h>
 #import <media/recordingmodel.h>
+#import <api/avmodel.h>
 
 // Ring
 #import "AppDelegate.h"
@@ -222,6 +223,7 @@ typedef NS_ENUM(NSInteger, ViewState) {
     NSResponder * viewNextResponder = [self nextResponder];
     [self setNextResponder: [conversationVC getMessagesView]];
     [[conversationVC getMessagesView] setNextResponder: viewNextResponder];
+    self.avModel->useAVFrame(YES);
 }
 
 - (void) connect
diff --git a/src/Shader.metal b/src/Shader.metal
new file mode 100644
index 0000000000000000000000000000000000000000..aa250f71798a867459053ace8d33af4f06635394
--- /dev/null
+++ b/src/Shader.metal
@@ -0,0 +1,75 @@
+/*
+ *  Copyright (C) 2019 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+#include <metal_stdlib>
+#include <simd/simd.h>
+using namespace metal;
+
+typedef enum VertexAttributes {
+    kVertexAttributePosition  = 0,
+    kVertexAttributeTexcoord  = 1,
+    } VertexAttributes;
+
+    typedef enum TextureIndices {
+        kTextureIndexColor  = 0,
+        kTextureIndexY      = 1,
+        kTextureIndexCbCr   = 2
+        } TextureIndices;
+
+        typedef struct {
+            float2 position [[attribute(kVertexAttributePosition)]];
+            float2 texCoord [[attribute(kVertexAttributeTexcoord)]];
+        } ImageVertex;
+
+        typedef struct {
+            float4 position [[position]];
+            float2 texCoord;
+        } ImageColorInOut;
+
+        struct Uniforms {
+            float4x4 projectionMatrix;
+            float4x4 rotationMatrix;
+        };
+
+        vertex ImageColorInOut imageVertex(ImageVertex in [[stage_in]],
+                                           constant Uniforms &uniforms [[buffer(1)]]) {
+            ImageColorInOut out;
+            out.position = uniforms.rotationMatrix * uniforms.projectionMatrix * float4(in.position, 1.0);
+            out.texCoord = in.texCoord;
+            return out;
+        }
+
+        fragment float4 imageFragment(ImageColorInOut in [[stage_in]],
+                                      texture2d<float, access::sample> capturedImageTextureY [[ texture(kTextureIndexY) ]],
+                                      texture2d<float, access::sample> capturedImageTextureCbCr [[ texture(kTextureIndexCbCr) ]]) {
+            constexpr sampler colorSampler(mip_filter::linear, mag_filter::linear, min_filter::linear);
+            const float4x4 ycbcrToRGBTransform = float4x4(float4(+1.0000f, +1.0000f, +1.0000f, +0.0000f),
+                                                          float4(+0.0000f, -0.3441f, +1.7720f, +0.0000f),
+                                                          float4(+1.4020f, -0.7141f, +0.0000f, +0.0000f),
+                                                          float4(-0.7010f, +0.5291f, -0.8860f, +1.0000f));
+
+            // Sample Y and CbCr textures to get the YCbCr color at the given texture coordinate
+            float4 ycbcr = float4(capturedImageTextureY.sample(colorSampler, in.texCoord).r,
+                                  capturedImageTextureCbCr.sample(colorSampler, in.texCoord).rg, 1.0);
+
+            return ycbcrToRGBTransform * ycbcr;
+        }
+
+
+
+
diff --git a/src/views/CallMTKView.h b/src/views/CallMTKView.h
new file mode 100644
index 0000000000000000000000000000000000000000..bbebd30f39cf2674d96ba63b7666b813182b1155
--- /dev/null
+++ b/src/views/CallMTKView.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2019 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <MetalKit/MetalKit.h>
+
+@interface CallMTKView: MTKView
+-(void)renderWithPixelBuffer:(CVPixelBufferRef)buffer size:(CGSize)size rotation: (float)rotation fillFrame: (bool)fill;
+-(void)fillWithBlack;
+@property bool stopRendering;
+@end
diff --git a/src/views/CallMTKView.mm b/src/views/CallMTKView.mm
new file mode 100644
index 0000000000000000000000000000000000000000..002ec8024b837017a7b6b845f7510ed263a2fa97
--- /dev/null
+++ b/src/views/CallMTKView.mm
@@ -0,0 +1,270 @@
+/*
+ *  Copyright (C) 2019 Savoir-faire Linux Inc.
+ *  Author: Kateryna Kostiuk <kateryna.kostiuk@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#import "CallMTKView.h"
+
+@implementation CallMTKView {
+     id <MTLBuffer> vertexBuffer;
+     id <MTLDepthStencilState> depthState;
+     id<MTLCommandQueue> commandQueue;
+     id<MTLRenderPipelineState> pipeline;
+     CVMetalTextureCacheRef textureCache;
+}
+
+// Vertex data for an image plane
+static const float kImagePlaneVertexData[16] = {
+    -1.0, -1.0,  0.0, 1.0,
+    1.0, -1.0,  1.0, 1.0,
+    -1.0,  1.0,  0.0, 0.0,
+    1.0,  1.0,  1.0, 0.0,
+};
+
+typedef enum BufferIndices {
+    kBufferIndexMeshPositions    = 0,
+} BufferIndices;
+
+typedef enum VertexAttributes {
+    kVertexAttributePosition  = 0,
+    kVertexAttributeTexcoord  = 1,
+} VertexAttributes;
+
+struct Uniforms {
+    simd::float4x4 projectionMatrix;
+    simd::float4x4 rotationMatrix;
+};
+
+- (instancetype)initWithFrame:(NSRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        id<MTLDevice> device = MTLCreateSystemDefaultDevice();
+        self.device = device;
+        commandQueue = [device newCommandQueue];
+        self.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
+        commandQueue = [device newCommandQueue];
+
+        CVReturn err = CVMetalTextureCacheCreate(kCFAllocatorDefault,
+                                                 NULL,
+                                                 self.device,
+                                                 NULL,
+                                                 &textureCache);
+
+        vertexBuffer = [device newBufferWithBytes:&kImagePlaneVertexData
+                                           length:sizeof(kImagePlaneVertexData)
+                                          options:MTLResourceCPUCacheModeDefaultCache];
+
+        NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
+        NSString *libraryPath = [resourcePath stringByAppendingPathComponent:@"Shader.metallib"];
+        id <MTLLibrary> library = [device newLibraryWithFile:libraryPath error:nil];
+        id<MTLFunction> vertexFunc = [library newFunctionWithName:@"imageVertex"];
+        id<MTLFunction> fragmentFunc = [library newFunctionWithName:@"imageFragment"];
+
+        // Create a vertex descriptor for our image plane vertex buffer
+        MTLVertexDescriptor *imagePlaneVertexDescriptor = [[MTLVertexDescriptor alloc] init];
+
+        // Positions.
+        imagePlaneVertexDescriptor.attributes[kVertexAttributePosition].format = MTLVertexFormatFloat2;
+        imagePlaneVertexDescriptor.attributes[kVertexAttributePosition].offset = 0;
+        imagePlaneVertexDescriptor.attributes[kVertexAttributePosition].bufferIndex = kBufferIndexMeshPositions;
+
+        // Texture coordinates.
+        imagePlaneVertexDescriptor.attributes[kVertexAttributeTexcoord].format = MTLVertexFormatFloat2;
+        imagePlaneVertexDescriptor.attributes[kVertexAttributeTexcoord].offset = 8;
+        imagePlaneVertexDescriptor.attributes[kVertexAttributeTexcoord].bufferIndex = kBufferIndexMeshPositions;
+
+        // Position Buffer Layout
+        imagePlaneVertexDescriptor.layouts[kBufferIndexMeshPositions].stride = 16;
+        imagePlaneVertexDescriptor.layouts[kBufferIndexMeshPositions].stepRate = 1;
+        imagePlaneVertexDescriptor.layouts[kBufferIndexMeshPositions].stepFunction = MTLVertexStepFunctionPerVertex;
+
+        MTLRenderPipelineDescriptor *pipelineDescriptor = [MTLRenderPipelineDescriptor new];
+        pipelineDescriptor.vertexFunction = vertexFunc;
+        pipelineDescriptor.fragmentFunction = fragmentFunc;
+        pipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
+        pipelineDescriptor.vertexDescriptor = imagePlaneVertexDescriptor;
+
+        pipeline = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:NULL];
+        MTLDepthStencilDescriptor *depthStateDescriptor = [[MTLDepthStencilDescriptor alloc] init];
+        depthStateDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
+        depthStateDescriptor.depthWriteEnabled = NO;
+        depthState = [device newDepthStencilStateWithDescriptor:depthStateDescriptor];
+        self.preferredFramesPerSecond = 30;
+    }
+    return self;
+}
+
+- (void)fillWithBlack {
+    NSUInteger width = self.frame.size.width;
+    NSUInteger height = self.frame.size.height;
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    uint8_t *rawData = (uint8_t *)calloc(height * width * 4, sizeof(uint8_t));
+    NSUInteger bytesPerPixel = 4;
+    NSUInteger bytesPerRow = bytesPerPixel * width;
+    NSUInteger bitsPerComponent = 8;
+    MTLTextureDescriptor *textureDescriptor =
+    [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
+                                                       width:width
+                                                      height:height
+                                                   mipmapped:YES];
+    textureDescriptor.usage = MTLTextureUsageRenderTarget;
+    id<MTLTexture> texture = [self.device newTextureWithDescriptor:textureDescriptor];
+    MTLRegion region = MTLRegionMake2D(0, 0, width, height);
+    [texture replaceRegion:region mipmapLevel:0 withBytes:rawData bytesPerRow:bytesPerRow];
+    id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
+    MTLRenderPassDescriptor *renderPass = self.currentRenderPassDescriptor;
+    id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPass];
+    [commandEncoder setFragmentTexture:texture atIndex:0];
+    [commandEncoder endEncoding];
+    [commandBuffer presentDrawable:self.currentDrawable];
+    [commandBuffer commit];
+}
+
+bool frameDisplayed = false;
+
+- (void)renderWithPixelBuffer:(CVPixelBufferRef)buffer
+                         size:(CGSize)size
+                     rotation: (float)rotation
+                    fillFrame: (bool)fill {
+    if(frameDisplayed) {
+        return;
+    }
+    if(_stopRendering) {
+        self.releaseDrawables;
+        return;
+    }
+    if (buffer == nil) return;
+    frameDisplayed = true;
+    CFRetain(buffer);
+    CVPixelBufferLockBaseAddress(buffer, 0);
+    id<MTLTexture> textureY = [self getTexture:buffer pixelFormat:MTLPixelFormatR8Unorm planeIndex:0];
+    id<MTLTexture> textureCbCr = [self getTexture:buffer pixelFormat:MTLPixelFormatRG8Unorm planeIndex:1];
+    CVPixelBufferUnlockBaseAddress(buffer, 0);
+    if(textureY == NULL || textureCbCr == NULL) {
+        frameDisplayed = false;
+        CVPixelBufferRelease(buffer);
+        return;
+    }
+    id<CAMetalDrawable> drawable = self.currentDrawable;
+    if (!drawable.texture) {
+        frameDisplayed = false;
+        CVPixelBufferRelease(buffer);
+        return;
+    }
+    NSSize frameSize = self.frame.size;
+
+    float viewRatio = (rotation == 90 || rotation == -90 || rotation == 180 || rotation == -180) ?
+    frameSize.height/frameSize.width : frameSize.width/frameSize.height;
+    float frameRatio = ((float)size.width)/((float)size.height);
+    simd::float4x4 projectionMatrix;
+    float ratio = viewRatio * (1/frameRatio);
+    if((viewRatio >= 1 && frameRatio >= 1) ||
+       (viewRatio < 1 && frameRatio < 1) ||
+       (ratio > 0.5 && ratio < 1.5) ) {
+        if (ratio <= 1.0 && ratio >= 0.5)
+            projectionMatrix = [self getScalingMatrix: 1/ratio axis: 'x'];
+        else if (ratio < 0.5)
+            projectionMatrix = [self getScalingMatrix: ratio axis: 'y'];
+        else if (ratio > 1 && ratio < 2)
+            projectionMatrix = [self getScalingMatrix: ratio axis: 'y'];
+        else
+            projectionMatrix = [self getScalingMatrix: 1/ratio axis: 'x'];
+    } else {
+        if (ratio < 1.0 && !fill || fill && ratio > 1.0)
+            projectionMatrix = [self getScalingMatrix: ratio axis: 'y'];
+        else
+            projectionMatrix = [self getScalingMatrix: 1/ratio axis: 'x'];
+    }
+    float radians = (-rotation * M_PI) / 180;
+    simd::float4x4 rotationMatrix = [self getRotationMatrix:radians];
+    Uniforms bytes = Uniforms{projectionMatrix: projectionMatrix, rotationMatrix: rotationMatrix};
+    id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
+    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> cbuffer) {
+        frameDisplayed = false;
+        CVPixelBufferRelease(buffer);
+    }];
+    MTLRenderPassDescriptor *renderPass = self.currentRenderPassDescriptor;
+    renderPass.colorAttachments[0].texture = drawable.texture;
+    id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPass];
+    [commandEncoder setRenderPipelineState: pipeline];
+    [commandEncoder setDepthStencilState:depthState];
+    [commandEncoder setVertexBytes: &bytes length:sizeof(bytes) atIndex:1];
+    [commandEncoder setVertexBuffer:vertexBuffer offset:0 atIndex:kBufferIndexMeshPositions];
+    [commandEncoder setFragmentTexture:textureY atIndex: 1];
+    [commandEncoder setFragmentTexture:textureCbCr atIndex:2];
+    [commandEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
+    [commandEncoder endEncoding];
+    [commandBuffer presentDrawable:drawable];
+    [commandBuffer commit];
+}
+
+-(simd::float4x4) getScalingMatrix:(CGFloat) ratio axis:(char) axis {
+    simd::float4x4 N = 0.0;
+    simd::float4 v[4] = {0.0, 0.0, 0.0, 0.0};
+    float xMultyplier = axis == 'x' ? ratio: 1;
+    float yMultyplier = axis == 'y' ? ratio: 1;
+    v[0] = { xMultyplier,  0,  0,  0 };
+    v[1] = {  0,  yMultyplier,  0,  0 };
+    v[2] = {  0,  0, 1, 0 };
+    v[3] = { 0, 0, 0, 1 };
+    N =  matrix_from_rows(v[0], v[1], v[2], v[3]);
+    return N;
+}
+
+-(simd::float4x4) getRotationMatrix:(float) rotation {
+    simd::float4x4 N = 0.0;
+    simd::float4 v[4] = {0.0, 0.0, 0.0, 0.0};
+    v[0] = {  cos(rotation),  sin(rotation),  0,  0 };
+    v[1] = {  -sin(rotation),  cos(rotation),  0,  0 };
+    v[2] = {  0,  0, 1, 0 };
+    v[3] = { 0, 0, 0, 1 };
+    N =  matrix_from_rows(v[0], v[1], v[2], v[3]);
+    return N;
+}
+
+- (id<MTLTexture>)getTexture:(CVPixelBufferRef)image pixelFormat:(MTLPixelFormat)pixelFormat planeIndex:(int)planeIndex {
+    id<MTLTexture> texture;
+    size_t width, height;
+    if (planeIndex == -1)
+    {
+        width = CVPixelBufferGetWidth(image);
+        height = CVPixelBufferGetHeight(image);
+        planeIndex = 0;
+    }
+    else
+    {
+        width = CVPixelBufferGetWidthOfPlane(image, planeIndex);
+        height = CVPixelBufferGetHeightOfPlane(image, planeIndex);
+    }
+    auto format = CVPixelBufferGetPixelFormatType(image);
+    CVMetalTextureRef textureRef = NULL;
+    CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, textureCache, image, NULL, pixelFormat, width, height, planeIndex, &textureRef);
+    if(status == kCVReturnSuccess)
+    {
+        texture = CVMetalTextureGetTexture(textureRef);
+        CFRelease(textureRef);
+    }
+    else
+    {
+        NSLog(@"CVMetalTextureCacheCreateTextureFromImage failed with return stats %d", status);
+        return NULL;
+    }
+    return texture;
+}
+
+@end
diff --git a/ui/Base.lproj/CurrentCall.xib b/ui/Base.lproj/CurrentCall.xib
index 9386c2ada92fb2f0d60193e1009723d1e0a48f15..38d0d199e619b8ae5271ab681d05ec74902eb2cb 100644
--- a/ui/Base.lproj/CurrentCall.xib
+++ b/ui/Base.lproj/CurrentCall.xib
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
     <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -45,6 +45,7 @@
                 <outlet property="stateLabel" destination="kFD-FB-vig" id="SSO-14-q2t"/>
                 <outlet property="timeSpentLabel" destination="cIU-M7-xpN" id="9Rl-t3-gjY"/>
                 <outlet property="transferButton" destination="aHZ-qL-mYf" id="9id-Nt-M7i"/>
+                <outlet property="videoMTKView" destination="gQE-fN-JhY" id="qca-wq-idt"/>
                 <outlet property="videoView" destination="2wf-Py-l6B" id="dEF-Gx-w6x"/>
                 <outlet property="view" destination="Hz6-mo-xeY" id="VKn-lN-ijP"/>
             </connections>
@@ -73,6 +74,9 @@
                                     </view>
                                     <color key="fillColor" name="labelColor" catalog="System" colorSpace="catalog"/>
                                 </box>
+                                <customView translatesAutoresizingMaskIntoConstraints="NO" id="gQE-fN-JhY" customClass="CallMTKView">
+                                    <rect key="frame" x="0.0" y="0.0" width="746" height="62"/>
+                                </customView>
                                 <customView translatesAutoresizingMaskIntoConstraints="NO" id="d0X-cW-Xgz">
                                     <rect key="frame" x="0.0" y="-10" width="746" height="72"/>
                                     <subviews>
@@ -120,6 +124,10 @@
                                                 <color key="backgroundColor" name="highlightColor" catalog="System" colorSpace="catalog"/>
                                             </textFieldCell>
                                         </textField>
+                                        <customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="L83-P5-9ao">
+                                            <rect key="frame" x="291" y="-12" width="163" height="96"/>
+                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+                                        </customView>
                                     </subviews>
                                     <constraints>
                                         <constraint firstItem="kFD-FB-vig" firstAttribute="leading" secondItem="bg3-hB-nE8" secondAttribute="leading" id="LXG-QI-oPf"/>
@@ -485,7 +493,7 @@
                                         <constraint firstItem="anb-Y8-JQi" firstAttribute="centerY" secondItem="Kjq-iM-NBL" secondAttribute="centerY" id="zA4-c4-mEX"/>
                                     </constraints>
                                 </customView>
-                                <customView translatesAutoresizingMaskIntoConstraints="NO" id="6y6-RH-qOp" userLabel="Preview">
+                                <customView translatesAutoresizingMaskIntoConstraints="NO" id="6y6-RH-qOp" userLabel="Preview" customClass="CallMTKView">
                                     <rect key="frame" x="551" y="20" width="175" height="120"/>
                                     <constraints>
                                         <constraint firstAttribute="height" constant="120" id="BvU-kV-0uD"/>
@@ -669,6 +677,7 @@
                             <constraints>
                                 <constraint firstAttribute="bottom" secondItem="Usy-W5-TGp" secondAttribute="bottom" id="5mb-Be-9o1"/>
                                 <constraint firstItem="Usy-W5-TGp" firstAttribute="top" secondItem="2wf-Py-l6B" secondAttribute="top" id="9ZC-hX-N5k"/>
+                                <constraint firstItem="gQE-fN-JhY" firstAttribute="trailing" secondItem="Usy-W5-TGp" secondAttribute="trailing" id="9cl-8g-a1Q"/>
                                 <constraint firstAttribute="bottom" secondItem="Eoi-B8-iL6" secondAttribute="bottom" constant="20" id="9j2-HZ-hNX"/>
                                 <constraint firstItem="W4l-Be-bhM" firstAttribute="centerY" secondItem="2wf-Py-l6B" secondAttribute="centerY" id="De3-8O-mXx"/>
                                 <constraint firstAttribute="trailing" secondItem="d0X-cW-Xgz" secondAttribute="trailing" id="G79-Jv-EYw"/>
@@ -676,6 +685,7 @@
                                 <constraint firstAttribute="trailing" secondItem="6y6-RH-qOp" secondAttribute="trailing" constant="20" id="KTx-SN-RUg"/>
                                 <constraint firstItem="d0X-cW-Xgz" firstAttribute="top" secondItem="2wf-Py-l6B" secondAttribute="top" id="MKB-zm-C75"/>
                                 <constraint firstItem="CDQ-nt-oe4" firstAttribute="leading" secondItem="Usy-W5-TGp" secondAttribute="leading" id="N2u-0C-Y3z"/>
+                                <constraint firstItem="gQE-fN-JhY" firstAttribute="leading" secondItem="Usy-W5-TGp" secondAttribute="leading" id="N5g-Mw-ag2"/>
                                 <constraint firstItem="se7-PJ-iwD" firstAttribute="width" secondItem="2wf-Py-l6B" secondAttribute="width" id="O1b-nk-1Y1"/>
                                 <constraint firstItem="peV-wm-HQm" firstAttribute="height" secondItem="2wf-Py-l6B" secondAttribute="height" id="O2u-BE-VPd"/>
                                 <constraint firstAttribute="trailing" secondItem="Usy-W5-TGp" secondAttribute="trailing" id="Pj0-Ck-gtP"/>
@@ -683,11 +693,13 @@
                                 <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="575" id="aB1-HF-No8"/>
                                 <constraint firstItem="CDQ-nt-oe4" firstAttribute="bottom" secondItem="Usy-W5-TGp" secondAttribute="bottom" id="agL-I1-x42"/>
                                 <constraint firstItem="d0X-cW-Xgz" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" id="efy-70-qsJ"/>
+                                <constraint firstItem="gQE-fN-JhY" firstAttribute="bottom" secondItem="Usy-W5-TGp" secondAttribute="bottom" id="fwu-m8-3Pt"/>
                                 <constraint firstItem="se7-PJ-iwD" firstAttribute="centerX" secondItem="2wf-Py-l6B" secondAttribute="centerX" id="hts-ke-nkj"/>
                                 <constraint firstItem="se7-PJ-iwD" firstAttribute="centerY" secondItem="2wf-Py-l6B" secondAttribute="centerY" id="kpo-pf-qt5"/>
                                 <constraint firstItem="W4l-Be-bhM" firstAttribute="centerX" secondItem="2wf-Py-l6B" secondAttribute="centerX" id="lvd-la-SAZ"/>
                                 <constraint firstItem="CDQ-nt-oe4" firstAttribute="top" secondItem="Usy-W5-TGp" secondAttribute="top" id="mS7-0s-mzr"/>
                                 <constraint firstItem="se7-PJ-iwD" firstAttribute="height" secondItem="2wf-Py-l6B" secondAttribute="height" id="nkk-DO-Hod"/>
+                                <constraint firstItem="gQE-fN-JhY" firstAttribute="top" secondItem="Usy-W5-TGp" secondAttribute="top" id="pVh-ja-gEo"/>
                                 <constraint firstItem="Eoi-B8-iL6" firstAttribute="leading" secondItem="2wf-Py-l6B" secondAttribute="leading" constant="20" id="sHw-xg-QAo"/>
                                 <constraint firstItem="peV-wm-HQm" firstAttribute="centerY" secondItem="2wf-Py-l6B" secondAttribute="centerY" id="siE-fo-i7E"/>
                                 <constraint firstItem="peV-wm-HQm" firstAttribute="centerX" secondItem="2wf-Py-l6B" secondAttribute="centerX" id="txG-gM-vYq"/>
@@ -1062,7 +1074,7 @@
         <userDefaultsController representsSharedInstance="YES" id="cb1-cg-dMu"/>
     </objects>
     <resources>
-        <image name="NSUser" width="128" height="128"/>
+        <image name="NSUser" width="32" height="32"/>
         <image name="ic_action_accept" width="72" height="72"/>
         <image name="ic_action_add_participant" width="72" height="72"/>
         <image name="ic_action_audio" width="36" height="36"/>