diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
index 7d7244201603ba73273c9bcd09448af967ab557a..b3348f4eae91b8fd848872e5dae56a8e9cd486e3 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
@@ -123,8 +123,6 @@ import cx.ring.utils.MediaButtonsHelper;
 import cx.ring.views.AvatarDrawable;
 import io.reactivex.disposables.CompositeDisposable;
 
-import static cx.ring.plugins.PluginUtils.loadPlugin;
-
 public class CallFragment extends BaseSupportFragment<CallPresenter> implements CallView, MediaButtonsHelper.MediaButtonsHelperCallback, RecyclerPickerLayoutManager.ItemSelectedListener {
 
     public static final String TAG = CallFragment.class.getSimpleName();
@@ -306,14 +304,21 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
         if (binding.videoSurface.getVisibility() == View.VISIBLE) {
             restartVideo = true;
         }
-        if (binding.previewContainer.getVisibility() == View.VISIBLE) {
-            restartPreview = true;
+        if (!pluginsMode) {
+            if (binding.previewContainer.getVisibility() == View.VISIBLE) {
+                restartPreview = true;
+            }
+        }else {
+            if (binding.pluginPreviewContainer.getVisibility() == View.VISIBLE) {
+                restartPreview = true;
+            }
         }
     }
 
     @Nullable
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+
         ((JamiApplication) requireActivity().getApplication()).getInjectionComponent().inject(this);
         binding = DataBindingUtil.inflate(inflater, R.layout.frag_call, container, false);
         binding.setPresenter(this);
@@ -331,6 +336,7 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
             mPreviewSurfaceWidth = width;
             mPreviewSurfaceHeight = height;
             presenter.previewVideoSurfaceCreated(binding.previewSurface);
+//            presenter.pluginSurfaceCreated(binding.pluginPreviewSurface);
         }
 
         @Override
@@ -343,6 +349,7 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
         @Override
         public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
             presenter.previewVideoSurfaceDestroyed();
+//            presenter.pluginSurfaceDestroyed();
             return true;
         }
 
@@ -356,7 +363,9 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
      */
     private void setPreviewDragHiddenState(float hiddenState) {
         binding.previewSurface.setAlpha(1.f - (3 * hiddenState / 4));
+        binding.pluginPreviewSurface.setAlpha(1.f - (3 * hiddenState / 4));
         binding.previewHandle.setAlpha(hiddenState);
+        binding.pluginPreviewHandle.setAlpha(hiddenState);
     }
 
     @SuppressLint("ClickableViewAccessibility")
@@ -416,6 +425,25 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
                 presenter.videoSurfaceDestroyed();
             }
         });
+
+        binding.pluginPreviewSurface.getHolder().setFormat(PixelFormat.RGBA_8888);
+        binding.pluginPreviewSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {
+                presenter.pluginSurfaceCreated(holder);
+            }
+
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+
+            }
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {
+                presenter.pluginSurfaceDestroyed();
+            }
+        });
+
         view.setOnSystemUiVisibilityChangeListener(visibility -> {
             boolean ui = (visibility & (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN)) == 0;
             presenter.uiVisibilityChanged(ui);
@@ -443,6 +471,8 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
         binding.shapeRipple.setRippleShape(new Circle());
         binding.callSpeakerBtn.setChecked(presenter.isSpeakerphoneOn());
         binding.callMicBtn.setChecked(presenter.isMicrophoneMuted());
+        binding.pluginPreviewSurface.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+                configureTransform(mPreviewSurfaceWidth, mPreviewSurfaceHeight));
         binding.previewSurface.setSurfaceTextureListener(listener);
         binding.previewSurface.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
                 configureTransform(mPreviewSurfaceWidth, mPreviewSurfaceHeight));
@@ -551,6 +581,102 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
             }
         });
 
+        binding.pluginPreviewContainer.setOnTouchListener((v, event) -> {
+            int action = event.getActionMasked();
+            RelativeLayout parent = (RelativeLayout) v.getParent();
+            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams();
+
+            if (action == MotionEvent.ACTION_DOWN) {
+                previewSnapAnimation.cancel();
+                previewDrag = new PointF(event.getX(), event.getY());
+                v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation_dragged));
+                params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+                params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+                params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+                params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+                params.setMargins((int) v.getX(), (int) v.getY(), parent.getWidth() - ((int) v.getX() + v.getWidth()), parent.getHeight() - ((int) v.getY() + v.getHeight()));
+                v.setLayoutParams(params);
+                return true;
+            } else if (action == MotionEvent.ACTION_MOVE) {
+                if (previewDrag != null) {
+                    int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
+                    int currentYPosition = params.topMargin + (int) (event.getY() - previewDrag.y);
+                    params.setMargins(
+                            currentXPosition,
+                            currentYPosition,
+                            -((currentXPosition + v.getWidth()) - (int) event.getX()),
+                            -((currentYPosition + v.getHeight()) - (int) event.getY()));
+                    v.setLayoutParams(params);
+
+                    float outPosition = binding.pluginPreviewContainer.getWidth() * 0.85f;
+                    float drapOut = 0.f;
+                    if (currentXPosition < 0) {
+                        drapOut = Math.min(1.f, -currentXPosition / outPosition);
+                    } else if (currentXPosition + v.getWidth() > parent.getWidth()) {
+                        drapOut = Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition);
+                    }
+                    setPreviewDragHiddenState(drapOut);
+                    return true;
+                }
+                return false;
+            } else if (action == MotionEvent.ACTION_UP) {
+                if (previewDrag != null) {
+                    int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
+
+                    previewSnapAnimation.cancel();
+                    previewDrag = null;
+                    v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation));
+                    int ml = 0, mr = 0, mt = 0, mb = 0;
+
+                    FrameLayout.LayoutParams hp = (FrameLayout.LayoutParams) binding.pluginPreviewHandle.getLayoutParams();
+                    if (params.leftMargin + (v.getWidth() / 2) > parent.getWidth() / 2) {
+                        params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
+                        params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+                        mr = (int) (parent.getWidth() - v.getWidth() - v.getX());
+                        previewPosition = PreviewPosition.RIGHT;
+                        hp.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
+                    } else {
+                        params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+                        params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+                        ml = (int) v.getX();
+                        previewPosition = PreviewPosition.LEFT;
+                        hp.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
+                    }
+                    binding.pluginPreviewHandle.setLayoutParams(hp);
+
+                    if (params.topMargin + (v.getHeight() / 2) > parent.getHeight() / 2) {
+                        params.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
+                        params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+                        mb = (int) (parent.getHeight() - v.getHeight() - v.getY());
+                    } else {
+                        params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+                        params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+                        mt = (int) v.getY();
+                    }
+                    previewMargins[0] = ml;
+                    previewMargins[1] = mt;
+                    previewMargins[2] = mr;
+                    previewMargins[3] = mb;
+                    params.setMargins(ml, mt, mr, mb);
+                    v.setLayoutParams(params);
+
+                    float outPosition = binding.pluginPreviewContainer.getWidth() * 0.85f;
+                    previewHiddenState = currentXPosition < 0
+                            ? Math.min(1.f, -currentXPosition / outPosition)
+                            : ((currentXPosition + v.getWidth() > parent.getWidth())
+                            ? Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition)
+                            : 0.f);
+                    setPreviewDragHiddenState(previewHiddenState);
+
+                    previewSnapAnimation.start();
+                    return true;
+                }
+                return false;
+            } else {
+                return false;
+            }
+        });
+
         binding.dialpadEditText.addTextChangedListener(new TextWatcher() {
             @Override
             public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -587,6 +713,7 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
                 (int) (previewMargins[2] * r + f - hideMargin),
                 (int) (previewMargins[3] * r + f));
         binding.previewContainer.setLayoutParams(params);
+        binding.pluginPreviewContainer.setLayoutParams(params);
     }
 
     /**
@@ -726,7 +853,15 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
     @Override
     public void displayVideoSurface(final boolean displayVideoSurface, final boolean displayPreviewContainer) {
         binding.videoSurface.setVisibility(displayVideoSurface ? View.VISIBLE : View.GONE);
-        binding.previewContainer.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
+        if (pluginsMode) {
+            binding.pluginPreviewSurface.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
+            binding.pluginPreviewContainer.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
+            binding.previewContainer.setVisibility(View.GONE);
+        } else {
+            binding.pluginPreviewSurface.setVisibility(View.GONE);
+            binding.pluginPreviewContainer.setVisibility(View.GONE);
+            binding.previewContainer.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
+        }
         updateMenu();
     }
 
@@ -929,6 +1064,16 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
         binding.previewSurface.setAspectRatio(flip ? mPreviewHeight : mPreviewWidth, flip ? mPreviewWidth : mPreviewHeight);
     }
 
+    @Override
+    public void resetPluginPreviewVideoSize(int previewWidth, int previewHeight, int rot) {
+        if (previewWidth == -1 && previewHeight == -1)
+            return;
+        mPreviewWidth = previewWidth;
+        mPreviewHeight = previewHeight;
+        boolean flip = (rot % 180) != 0;
+        binding.pluginPreviewSurface.setAspectRatio(flip ? mPreviewHeight : mPreviewWidth, flip ? mPreviewWidth : mPreviewHeight);
+    }
+
     @Override
     public void resetVideoSize(int videoWidth, int videoHeight) {
         ViewGroup rootView = (ViewGroup) getView();
@@ -978,7 +1123,12 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
         } else if (Surface.ROTATION_180 == rotation) {
             matrix.postRotate(180, centerX, centerY);
         }
-        binding.previewSurface.setTransform(matrix);
+        if(!pluginsMode) {
+//            binding.pluginPreviewSurface.setTransform(matrix);
+//        }
+//        else {
+            binding.previewSurface.setTransform(matrix);
+        }
     }
 
     @Override
@@ -1090,14 +1240,24 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
 
     private void startScreenShare(MediaProjection mediaProjection) {
         if (presenter.startScreenShare(mediaProjection)) {
-            binding.previewSurface.setVisibility(View.GONE);
+            if(pluginsMode) {
+                binding.pluginPreviewSurface.setVisibility(View.GONE);
+            } else {
+                binding.previewSurface.setVisibility(View.GONE);
+            }
         } else {
             Toast.makeText(requireContext(), "Can't start screen sharing", Toast.LENGTH_SHORT).show();
         }
     }
 
     private void stopShareScreen() {
-        binding.previewSurface.setVisibility(View.VISIBLE);
+        if(pluginsMode)
+        {
+            binding.previewSurface.setVisibility(View.VISIBLE);
+        }
+        else {
+            binding.previewSurface.setVisibility(View.VISIBLE);
+        }
         presenter.stopScreenShare();
     }
 
@@ -1218,6 +1378,7 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
      */
     public void displayVideoPluginsCarousel() {
         pluginsMode = !pluginsMode;
+
         Context context = requireActivity();
 
         // Create callMediaHandlers and videoPluginsItems in a lazy manner
@@ -1246,6 +1407,8 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
         }
 
         if (pluginsMode) {
+            //change preview image
+            displayVideoSurface(true,true);
             // hide hang up button and other call buttons
             displayHangupButton(false);
             // Display the plugins recyclerpicker
@@ -1262,6 +1425,8 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements
             }
 
         } else {
+            //change preview image
+            displayVideoSurface(true,true);
             if (previousPluginPosition != -1) {
                 String callMediaId = callMediaHandlers.
                         get(previousPluginPosition);
diff --git a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
index 8d7561c093b38f30abb8803bc6449357e1194cb4..972d48b95d5b7e8b969d55dc5e090c0084cb83d3 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
@@ -502,6 +502,16 @@ public class TVCallFragment extends BaseSupportFragment<CallPresenter> implement
         binding.previewSurface.setAspectRatio(flip ? mPreviewHeight : mPreviewWidth, flip ? mPreviewWidth : mPreviewHeight);
     }
 
+    @Override
+    public void resetPluginPreviewVideoSize(int previewWidth, int previewHeight, int rot) {
+        if (previewWidth == -1 && previewHeight == -1)
+            return;
+        mPreviewWidth = previewWidth;
+        mPreviewHeight = previewHeight;
+        boolean flip = (rot % 180) != 0;
+        binding.pluginPreviewSurface.setAspectRatio(flip ? mPreviewHeight : mPreviewWidth, flip ? mPreviewWidth : mPreviewHeight);
+    }
+
     @Override
     public void resetVideoSize(final int videoWidth, final int videoHeight) {
         ViewGroup rootView = (ViewGroup) getView();
diff --git a/ring-android/app/src/main/java/cx/ring/views/AutoFitSurfaceView.java b/ring-android/app/src/main/java/cx/ring/views/AutoFitSurfaceView.java
new file mode 100644
index 0000000000000000000000000000000000000000..67c3a50ae23b41d6d99dfa5a1d8a4baaf0f2df0e
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/views/AutoFitSurfaceView.java
@@ -0,0 +1,79 @@
+package cx.ring.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.SurfaceView;
+import android.view.TextureView;
+
+import androidx.core.view.ViewCompat;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A {@link TextureView} that can be adjusted to a specified aspect ratio.
+ */
+public class AutoFitSurfaceView extends SurfaceView {
+
+    private int mRatioWidth = 720;
+    private int mRatioHeight = 1280;
+    private final int mSize;
+    private final List<Rect> mBounds = Collections.singletonList(new Rect());
+
+    public AutoFitSurfaceView(Context context) {
+        this(context, null);
+    }
+
+    public AutoFitSurfaceView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AutoFitSurfaceView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mSize = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 192, context.getResources().getDisplayMetrics()));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        mBounds.get(0).set(left, top, right, bottom);
+        ViewCompat.setSystemGestureExclusionRects(this, mBounds);
+    }
+
+    /**
+     * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
+     * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
+     * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
+     *
+     * @param width  Relative horizontal size
+     * @param height Relative vertical size
+     */
+    public void setAspectRatio(int width, int height) {
+        if (width < 0 || height < 0) {
+            throw new IllegalArgumentException("Size cannot be negative.");
+        }
+        if (mRatioWidth != width || mRatioHeight != height) {
+            mRatioWidth = width;
+            mRatioHeight = height;
+            requestLayout();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int width = Math.min(MeasureSpec.getSize(widthMeasureSpec), mSize);
+        int height = Math.min(MeasureSpec.getSize(heightMeasureSpec), mSize);
+        if (0 == mRatioWidth || 0 == mRatioHeight) {
+            setMeasuredDimension(width, height);
+        } else {
+            if (width < height * mRatioWidth / mRatioHeight) {
+                setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
+            } else {
+                setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
+            }
+        }
+    }
+}
diff --git a/ring-android/app/src/main/res/layout/frag_call.xml b/ring-android/app/src/main/res/layout/frag_call.xml
index 8702418e2bea97a88e6759d7b7b1fc6f4cfe4a08..631d16713e3a78f536e2633593c5ef97c7f61f72 100644
--- a/ring-android/app/src/main/res/layout/frag_call.xml
+++ b/ring-android/app/src/main/res/layout/frag_call.xml
@@ -47,6 +47,40 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                 android:visibility="gone"
                 tools:visibility="visible" />
 
+            <androidx.cardview.widget.CardView
+                android:id="@+id/plugin_preview_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentRight="true"
+                android:layout_alignParentBottom="true"
+                android:layout_marginLeft="@dimen/call_preview_margin"
+                android:layout_marginTop="@dimen/call_preview_margin"
+                android:layout_marginBottom="@dimen/call_preview_margin"
+                android:layout_marginRight="@dimen/call_preview_margin"
+                android:visibility="gone"
+                app:cardCornerRadius="16dp"
+                app:cardPreventCornerOverlap="false"
+                tools:visibility="visible"
+                app:cardBackgroundColor="@color/black">
+
+                <cx.ring.views.AutoFitSurfaceView
+                    android:id="@+id/plugin_preview_surface"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:visibility="visible"/>
+
+                <ImageView
+                    android:id="@+id/plugin_preview_handle"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="left|center_vertical"
+                    android:layout_marginHorizontal="@dimen/call_preview_margin_handle"
+                    android:visibility="visible"
+                    android:alpha="0"
+                    app:srcCompat="@drawable/ic_preview_handle" />
+
+            </androidx.cardview.widget.CardView>
+
             <androidx.cardview.widget.CardView
                 android:id="@+id/preview_container"
                 android:layout_width="wrap_content"
diff --git a/ring-android/app/src/main/res/layout/tv_frag_call.xml b/ring-android/app/src/main/res/layout/tv_frag_call.xml
index f2c2c20304bca5f24cb68c0686f0f231e04b5501..5af32cb9c758228d896607e9b188fd8ddcf6dcd6 100644
--- a/ring-android/app/src/main/res/layout/tv_frag_call.xml
+++ b/ring-android/app/src/main/res/layout/tv_frag_call.xml
@@ -63,6 +63,25 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                 tools:visibility="visible" />
         </androidx.cardview.widget.CardView>
 
+        <androidx.cardview.widget.CardView
+            android:id="@+id/plugin_preview_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentBottom="true"
+            android:layout_margin="12dp"
+            android:visibility="gone"
+            app:cardCornerRadius="16dp"
+            app:cardPreventCornerOverlap="false">
+
+            <cx.ring.views.AutoFitTextureView
+                android:id="@+id/plugin_preview_surface"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="visible"
+                tools:visibility="visible" />
+        </androidx.cardview.widget.CardView>
+
         <LinearLayout
             android:id="@+id/contact_bubble_layout"
             android:layout_width="match_parent"
diff --git a/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
index 4f521fc1e1aa5aaf472590ff91202f7130d0b1b1..304a91ae20e84612ff55b2904471f937496423d0 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
@@ -29,6 +29,7 @@ import javax.inject.Inject;
 import javax.inject.Named;
 
 import cx.ring.daemon.Ringservice;
+import cx.ring.daemon.RingserviceJNI;
 import cx.ring.facades.ConversationFacade;
 import cx.ring.model.Conference;
 import cx.ring.model.Conversation;
@@ -50,6 +51,9 @@ import io.reactivex.disposables.Disposable;
 import io.reactivex.subjects.BehaviorSubject;
 import io.reactivex.subjects.Subject;
 
+import static cx.ring.daemon.Ringservice.listCallMediaHandlers;
+import static cx.ring.daemon.Ringservice.toggleCallMediaHandler;
+
 public class CallPresenter extends RootPresenter<CallView> {
 
     public final static String TAG = CallPresenter.class.getSimpleName();
@@ -77,6 +81,7 @@ public class CallPresenter extends RootPresenter<CallView> {
     private int previewWidth = -1;
     private int previewHeight = -1;
     private String currentSurfaceId = null;
+    private String currentPluginSurfaceId = null;
 
     private Disposable timeUpdateTask = null;
 
@@ -277,6 +282,13 @@ public class CallPresenter extends RootPresenter<CallView> {
     }
 
     public void hangupCall() {
+        List<String> callMediaHandlers = listCallMediaHandlers();
+
+        for (String callMediaHandler : callMediaHandlers)
+        {
+            toggleCallMediaHandler(callMediaHandler, false);
+        }
+
         if (mConference != null) {
             if (mConference.isConference())
                 mCallService.hangUpConference(mConference.getId());
@@ -317,6 +329,26 @@ public class CallPresenter extends RootPresenter<CallView> {
         }
     }
 
+    public void pluginSurfaceCreated(Object holder) {
+        if (mConference == null) {
+            return;
+        }
+        String newId = mConference.getPluginId();
+        if (!newId.equals(currentPluginSurfaceId)) {
+            mHardwareService.removeVideoSurface(currentPluginSurfaceId);
+            currentPluginSurfaceId = newId;
+        }
+        mHardwareService.addVideoSurface(mConference.getPluginId(), holder);
+        getView().displayContactBubble(false);
+    }
+
+    public void pluginSurfaceUpdateId(String newId) {
+        if (!Objects.equals(newId, currentPluginSurfaceId)) {
+            mHardwareService.updateVideoSurfaceId(currentPluginSurfaceId, newId);
+            currentPluginSurfaceId = newId;
+        }
+    }
+
     public void previewVideoSurfaceCreated(Object holder) {
         mHardwareService.addPreviewVideoSurface(holder, mConference);
         //mHardwareService.startCapture(null);
@@ -328,7 +360,12 @@ public class CallPresenter extends RootPresenter<CallView> {
             currentSurfaceId = null;
         }
     }
-
+    public void pluginSurfaceDestroyed() {
+        if (currentPluginSurfaceId != null) {
+            mHardwareService.removeVideoSurface(currentPluginSurfaceId);
+            currentPluginSurfaceId = null;
+        }
+    }
     public void previewVideoSurfaceDestroyed() {
         mHardwareService.removePreviewVideoSurface();
         mHardwareService.endCapture();
@@ -428,6 +465,7 @@ public class CallPresenter extends RootPresenter<CallView> {
                 mHardwareService.setPreviewSettings();
                 mHardwareService.updatePreviewVideoSurface(mConference);
                 videoSurfaceUpdateId(call.getId());
+                pluginSurfaceUpdateId(call.getPluginId());
                 view.displayVideoSurface(true, mDeviceRuntimeService.hasVideoPermission());
                 if (permissionChanged) {
                     mHardwareService.switchInput(mConference.getId(), permissionChanged);
@@ -491,6 +529,13 @@ public class CallPresenter extends RootPresenter<CallView> {
                 getView().resetPreviewVideoSize(previewWidth, previewHeight, event.rot);
             }
         }
+        if (mConference != null && mConference.getPluginId().equals(event.callId)) {
+            if (event.started) {
+                previewWidth = event.w;
+                previewHeight = event.h;
+                getView().resetPluginPreviewVideoSize(previewWidth, previewHeight, event.rot);
+            }
+        }
         /*if (event.started || event.start) {
             getView().resetVideoSize(videoWidth, videoHeight, previewWidth, previewHeight);
         }*/
diff --git a/ring-android/libringclient/src/main/java/cx/ring/call/CallView.java b/ring-android/libringclient/src/main/java/cx/ring/call/CallView.java
index ce9483c1c502b8c811c92a6131537d83e6eb6372..757404d27cdf7442490c04109d29b2b2780feba7 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/call/CallView.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/call/CallView.java
@@ -32,6 +32,7 @@ public interface CallView {
     void displayContactBubble(boolean display);
 
     void displayVideoSurface(boolean displayVideoSurface, boolean displayPreviewContainer);
+//    void displayPluginSurface();
 
     void displayPreviewSurface(boolean display);
 
@@ -59,6 +60,7 @@ public interface CallView {
     void initOutGoingCallDisplay();
 
     void resetPreviewVideoSize(int previewWidth, int previewHeight, int rot);
+    void resetPluginPreviewVideoSize(int previewWidth, int previewHeight, int rot);
     void resetVideoSize(int videoWidth, int videoHeight);
 
     void goToConversation(String accountId, String conversationId);
diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/Conference.java b/ring-android/libringclient/src/main/java/cx/ring/model/Conference.java
index 44e95f26fa67489dbfa1902702445a67df34f9d2..484ff5d472b527cba2ca2f7c495e368f2ea7e775 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/model/Conference.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/model/Conference.java
@@ -72,6 +72,10 @@ public class Conference {
         }
     }
 
+    public String getPluginId() {
+        return mId + "_plugin";
+    }
+
     public String getConfId() {
         return mId;
     }
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/HardwareService.java b/ring-android/libringclient/src/main/java/cx/ring/services/HardwareService.java
index d7690732bd90a24a0734f6d7e87a5d9ef6faf115..b1b52deda90ed3296c3f6ac107c0321c854e3bdd 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/services/HardwareService.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/HardwareService.java
@@ -185,10 +185,8 @@ public abstract class HardwareService {
         if (inputWindow == 0) {
             return inputWindow;
         }
-
         RingserviceJNI.setNativeWindowGeometry(inputWindow, width, height);
         RingserviceJNI.registerVideoCallback(inputId, inputWindow);
-
         return inputWindow;
     }