diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt
index 833855a0..5b98b27d 100644
--- a/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt
+++ b/android/app/src/main/kotlin/com/hmg/hmgDr/ui/fragment/VideoCallFragment.kt
@@ -27,6 +27,8 @@ import com.hmg.hmgDr.ui.VideoCallContract.VideoCallPresenter
 import com.hmg.hmgDr.ui.VideoCallContract.VideoCallView
 import com.hmg.hmgDr.ui.VideoCallPresenterImpl
 import com.hmg.hmgDr.ui.VideoCallResponseListener
+import com.hmg.hmgDr.util.DynamicVideoRenderer
+import com.hmg.hmgDr.util.ThumbnailCircleVideoRenderer
 import com.opentok.android.*
 import com.opentok.android.PublisherKit.PublisherListener
 import pub.devrel.easypermissions.AfterPermissionGranted
@@ -60,6 +62,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
     private var mVolRunnable: Runnable? = null
     private var mConnectedRunnable: Runnable? = null
 
+    private lateinit var thumbnail_container: FrameLayout
     private lateinit var mPublisherViewContainer: FrameLayout
     private lateinit var mPublisherViewIcon: View
     private lateinit var mSubscriberViewContainer: FrameLayout
@@ -220,6 +223,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
         layoutName = view.findViewById(R.id.layout_name)
         layoutMini = view.findViewById(R.id.layout_mini)
         icMini = view.findViewById(R.id.ic_mini)
+        thumbnail_container = view.findViewById(R.id.thumbnail_container)
         mPublisherViewContainer = view.findViewById(R.id.local_video_view_container)
         mPublisherViewIcon = view.findViewById(R.id.local_video_view_icon)
         mSubscriberViewIcon = view.findViewById(R.id.remote_video_view_icon)
@@ -345,12 +349,16 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
 
     override fun onConnected(session: Session?) {
         Log.i(TAG, "Session Connected")
-        mPublisher = Publisher.Builder(requireContext()).build()
+        mPublisher = Publisher.Builder(requireContext())
+//                .name("publisher")
+//                .renderer(ThumbnailCircleVideoRenderer(requireContext()))
+                .build()
         mPublisher!!.setPublisherListener(this)
-        mPublisherViewContainer.addView(mPublisher!!.view)
-        if (mPublisher!!.getView() is GLSurfaceView) {
-            (mPublisher!!.getView() as GLSurfaceView).setZOrderOnTop(true)
+        if (mPublisher!!.view is GLSurfaceView) {
+            (mPublisher!!.view as GLSurfaceView).setZOrderOnTop(true)
         }
+
+        mPublisherViewContainer.addView(mPublisher!!.view)
         mSession!!.publish(mPublisher)
 
         if (!resume) {
@@ -368,7 +376,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
     override fun onError(session: Session, opentokError: OpentokError) {
         Log.d(TAG, "onError: Error (" + opentokError.message + ") in session " + session.sessionId)
 
-       // videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in session ")
+        // videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in session ")
 //        dialog?.dismiss()
     }
 
@@ -391,7 +399,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
             return
         }
         if (mSubscriber!!.stream == stream) {
-            mSubscriberViewContainer!!.removeView(mSubscriber!!.view)
+            mSubscriberViewContainer.removeView(mSubscriber!!.view)
             mSubscriber!!.destroy()
             mSubscriber = null
         }
@@ -408,13 +416,49 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
 
     override fun onError(publisherKit: PublisherKit?, opentokError: OpentokError) {
         Log.d(VideoCallFragment.TAG, "onError: Error (" + opentokError.message + ") in publisher")
-       // videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in publisher")
+        // videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in publisher")
 //        dialog?.dismiss()
     }
 
     override fun onVideoDataReceived(subscriberKit: SubscriberKit?) {
         mSubscriber!!.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL)
-        mSubscriberViewContainer!!.addView(mSubscriber!!.view)
+        (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false)
+        mSubscriberViewContainer.addView(mSubscriber!!.view)
+//        switchToThumbnailCircle()
+    }
+
+    fun switchToThumbnailCircle() {
+        thumbnail_container.postDelayed({
+            val view = mSubscriber!!.view
+            if (view.parent != null) {
+                (view.parent as ViewGroup).removeView(view)
+            }
+            if (view is GLSurfaceView) {
+                view.setZOrderOnTop(true)
+                if (mSubscriber!!.renderer is DynamicVideoRenderer) {
+                    (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(true)
+                    thumbnail_container.addView(view)
+                }
+            }
+            switchToFullScreenView()
+        }, 4000)
+    }
+
+    fun switchToFullScreenView() {
+        mSubscriberViewContainer.postDelayed({
+            val view = mSubscriber!!.view
+            if (view.parent != null) {
+                (view.parent as ViewGroup).removeView(view)
+            }
+            if (view is GLSurfaceView) {
+                view.setZOrderOnTop(false)
+                if (mSubscriber!!.renderer is DynamicVideoRenderer) {
+                    (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false)
+                    mSubscriberViewContainer.addView(view)
+                }
+            }
+            switchToThumbnailCircle()
+        }, 4000)
     }
 
     override fun onVideoDisabled(subscriberKit: SubscriberKit?, s: String?) {}
@@ -426,7 +470,9 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
     override fun onVideoDisableWarningLifted(subscriberKit: SubscriberKit?) {}
 
     private fun subscribeToStream(stream: Stream) {
-        mSubscriber = Subscriber.Builder(requireContext(), stream).build()
+        mSubscriber = Subscriber.Builder(requireContext(), stream)
+                .renderer(DynamicVideoRenderer(requireContext()))
+                .build()
         mSubscriber!!.setVideoListener(this)
         mSession!!.subscribe(mSubscriber)
     }
@@ -488,31 +534,29 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
         disconnectSession()
     }
 
-    private fun miniCircleDoubleTap(){
-        if (isCircle){
+    private fun miniCircleDoubleTap() {
+        if (isCircle) {
             onMiniCircleClicked()
         }
     }
 
-    private fun onMiniCircleClicked(){
+    private fun onMiniCircleClicked() {
         if (isCircle) {
             dialog?.window?.setLayout(
                     400,
                     600
             )
-            videoCallContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color))
-            mSubscriberViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.remoteBackground))
+            (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false)
         } else {
             dialog?.window?.setLayout(
-                    200,
-                    200
+                    300,
+                    300
             )
-            videoCallContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
-            mSubscriberViewContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
+            (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(true)
         }
         isCircle = !isCircle
 
-        if(isCircle){
+        if (isCircle) {
             controlPanel.visibility = View.GONE
             layoutMini.visibility = View.GONE
         } else {
@@ -548,16 +592,16 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
         val btnMinimizeLayoutParam: ConstraintLayout.LayoutParams = btnMinimize.layoutParams as ConstraintLayout.LayoutParams
         val mCallBtnLayoutParam: ConstraintLayout.LayoutParams = mCallBtn.layoutParams as ConstraintLayout.LayoutParams
 
-        val localPreviewMargin : Int = context!!.resources.getDimension(R.dimen.local_preview_margin_top).toInt()
-        val localPreviewWidth : Int = context!!.resources.getDimension(R.dimen.local_preview_width).toInt()
-        val localPreviewHeight : Int = context!!.resources.getDimension(R.dimen.local_preview_height).toInt()
+        val localPreviewMargin: Int = context!!.resources.getDimension(R.dimen.local_preview_margin_top).toInt()
+        val localPreviewWidth: Int = context!!.resources.getDimension(R.dimen.local_preview_width).toInt()
+        val localPreviewHeight: Int = context!!.resources.getDimension(R.dimen.local_preview_height).toInt()
 //        val localPreviewIconSize: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size).toInt()
 //        val localPreviewMarginSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_margin_small).toInt()
 //        val localPreviewWidthSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_width_small).toInt()
 //        val localPreviewHeightSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_height_small).toInt()
 //        val localPreviewIconSmall: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size_small).toInt()
 //        val localPreviewLayoutIconParam : FrameLayout.LayoutParams
-        val localPreviewLayoutParam : RelativeLayout.LayoutParams = mPublisherViewContainer.layoutParams as RelativeLayout.LayoutParams
+        val localPreviewLayoutParam: RelativeLayout.LayoutParams = mPublisherViewContainer.layoutParams as RelativeLayout.LayoutParams
 
         val remotePreviewIconSize: Int = context!!.resources.getDimension(R.dimen.remote_back_icon_size).toInt()
         val remotePreviewIconSizeSmall: Int = context!!.resources.getDimension(R.dimen.remote_back_icon_size_small).toInt()
@@ -611,7 +655,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
             remotePreviewLayoutParam.width = remotePreviewIconSizeSmall
             remotePreviewLayoutParam.height = remotePreviewIconSizeSmall
 
-            if(isCircle){
+            if (isCircle) {
                 controlPanel.visibility = View.GONE
                 layoutMini.visibility = View.GONE
             } else {
@@ -651,7 +695,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
             isSpeckerClicked = !isSpeckerClicked
             mSubscriber!!.subscribeToAudio = !isSpeckerClicked
             val res = if (isSpeckerClicked) R.drawable.audio_disabled else R.drawable.audio_enabled
-            mspeckerBtn!!.setImageResource(res)
+            mspeckerBtn.setImageResource(res)
         }
     }
 
@@ -722,7 +766,7 @@ class VideoCallFragment : DialogFragment(), PermissionCallbacks, Session.Session
     }
 
     private fun showControlPanelTemporarily() {
-        if (!isCircle){
+        if (!isCircle) {
             controlPanel.visibility = View.VISIBLE
             mVolHandler!!.removeCallbacks(mVolRunnable!!)
             mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/util/DynamicVideoRenderer.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/util/DynamicVideoRenderer.kt
new file mode 100644
index 00000000..1a307eb5
--- /dev/null
+++ b/android/app/src/main/kotlin/com/hmg/hmgDr/util/DynamicVideoRenderer.kt
@@ -0,0 +1,379 @@
+package com.hmg.hmgDr.util
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.PixelFormat
+import android.opengl.GLES20
+import android.opengl.GLSurfaceView
+import android.opengl.Matrix
+import android.view.View
+import com.opentok.android.BaseVideoRenderer
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+import java.nio.FloatBuffer
+import java.nio.ShortBuffer
+import java.util.concurrent.locks.ReentrantLock
+import javax.microedition.khronos.egl.EGLConfig
+import javax.microedition.khronos.opengles.GL10
+
+/*
+* https://nhancv.medium.com/android-how-to-make-a-circular-view-as-a-thumbnail-of-opentok-27992aee15c9
+* to solve make circle video stream
+* */
+
+class DynamicVideoRenderer(private val mContext: Context) : BaseVideoRenderer() {
+    private val mView: GLSurfaceView = GLSurfaceView(mContext)
+    private val mRenderer: MyRenderer
+
+    interface DynamicVideoRendererMetadataListener {
+        fun onMetadataReady(metadata: ByteArray?)
+    }
+
+    fun setDynamicVideoRendererMetadataListener(metadataListener: DynamicVideoRendererMetadataListener?) {
+        mRenderer.metadataListener = metadataListener
+    }
+
+    fun enableThumbnailCircle(enable: Boolean) {
+        mRenderer.requestEnableThumbnailCircle = enable
+    }
+
+    internal class MyRenderer : GLSurfaceView.Renderer {
+        var mTextureIds = IntArray(3)
+        var mScaleMatrix = FloatArray(16)
+        private val mVertexBuffer: FloatBuffer
+        private val mTextureBuffer: FloatBuffer
+        private val mDrawListBuffer: ShortBuffer
+        var requestEnableThumbnailCircle = false
+        var mVideoFitEnabled = true
+        var mVideoDisabled = false
+        private val mVertexIndex = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw
+
+        // vertices
+        private val vertexShaderCode = """uniform mat4 uMVPMatrix;attribute vec4 aPosition;
+attribute vec2 aTextureCoord;
+varying vec2 vTextureCoord;
+void main() {
+  gl_Position = uMVPMatrix * aPosition;
+  vTextureCoord = aTextureCoord;
+}
+"""
+        private val fragmentShaderCode = """precision mediump float;
+uniform sampler2D Ytex;
+uniform sampler2D Utex,Vtex;
+uniform int enableCircle;
+uniform vec2 radiusDp;
+varying vec2 vTextureCoord;
+void main(void) {
+  float nx,ny,r,g,b,y,u,v;
+  mediump vec4 txl,ux,vx;  nx=vTextureCoord[0];
+  ny=vTextureCoord[1];
+  y=texture2D(Ytex,vec2(nx,ny)).r;
+  u=texture2D(Utex,vec2(nx,ny)).r;
+  v=texture2D(Vtex,vec2(nx,ny)).r;
+  y=1.1643*(y-0.0625);
+  u=u-0.5;
+  v=v-0.5;
+  r=y+1.5958*v;
+  g=y-0.39173*u-0.81290*v;
+  b=y+2.017*u;
+  if (enableCircle > 0) { 
+    float radius = 0.5;
+    vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);
+    vec4 color1 = vec4(r, g, b, 1.0);
+    vec2 st = (gl_FragCoord.xy/radiusDp.xy);    float dist = radius - distance(st,vec2(0.5));
+    float t = 1.0;
+    if (dist < 0.0) t = 0.0;
+    gl_FragColor = mix(color0, color1, t);
+  }
+  else {
+    gl_FragColor = vec4(r, g, b, 1.0);
+  }
+}
+"""
+        var mFrameLock = ReentrantLock()
+        var mCurrentFrame: Frame? = null
+        private var mProgram = 0
+        private var mTextureWidth = 0
+        private var mTextureHeight = 0
+        private var mViewportWidth = 0
+        private var mViewportHeight = 0
+        override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
+            gl.glClearColor(0f, 0f, 0f, 1f)
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
+            val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
+                    vertexShaderCode)
+            val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
+                    fragmentShaderCode)
+            mProgram = GLES20.glCreateProgram() // create empty OpenGL ES
+            // Program
+            GLES20.glAttachShader(mProgram, vertexShader) // add the vertex
+            // shader to program
+            GLES20.glAttachShader(mProgram, fragmentShader) // add the fragment
+            // shader to
+            // program
+            GLES20.glLinkProgram(mProgram)
+            val positionHandle = GLES20.glGetAttribLocation(mProgram,
+                    "aPosition")
+            val textureHandle = GLES20.glGetAttribLocation(mProgram,
+                    "aTextureCoord")
+            GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
+                    GLES20.GL_FLOAT, false, COORDS_PER_VERTEX * 4,
+                    mVertexBuffer)
+            GLES20.glEnableVertexAttribArray(positionHandle)
+            GLES20.glVertexAttribPointer(textureHandle,
+                    TEXTURECOORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
+                    TEXTURECOORDS_PER_VERTEX * 4, mTextureBuffer)
+            GLES20.glEnableVertexAttribArray(textureHandle)
+            GLES20.glUseProgram(mProgram)
+            var i = GLES20.glGetUniformLocation(mProgram, "Ytex")
+            GLES20.glUniform1i(i, 0) /* Bind Ytex to texture unit 0 */
+            i = GLES20.glGetUniformLocation(mProgram, "Utex")
+            GLES20.glUniform1i(i, 1) /* Bind Utex to texture unit 1 */
+            i = GLES20.glGetUniformLocation(mProgram, "Vtex")
+            GLES20.glUniform1i(i, 2) /* Bind Vtex to texture unit 2 */
+            val radiusDpLocation = GLES20.glGetUniformLocation(mProgram, "radiusDp")
+            val radiusDp = (Resources.getSystem().displayMetrics.density * THUMBNAIL_SIZE).toInt()
+            GLES20.glUniform2f(radiusDpLocation, radiusDp.toFloat(), radiusDp.toFloat())
+            mTextureWidth = 0
+            mTextureHeight = 0
+        }
+
+        fun enableThumbnailCircle(enable: Boolean) {
+            GLES20.glUseProgram(mProgram)
+            val enableCircleLocation = GLES20.glGetUniformLocation(mProgram, "enableCircle")
+            GLES20.glUniform1i(enableCircleLocation, if (enable) 1 else 0)
+        }
+
+        fun setupTextures(frame: Frame) {
+            if (mTextureIds[0] != 0) {
+                GLES20.glDeleteTextures(3, mTextureIds, 0)
+            }
+            GLES20.glGenTextures(3, mTextureIds, 0)
+            val w = frame.width
+            val h = frame.height
+            val hw = w + 1 shr 1
+            val hh = h + 1 shr 1
+            initializeTexture(GLES20.GL_TEXTURE0, mTextureIds[0], w, h)
+            initializeTexture(GLES20.GL_TEXTURE1, mTextureIds[1], hw, hh)
+            initializeTexture(GLES20.GL_TEXTURE2, mTextureIds[2], hw, hh)
+            mTextureWidth = frame.width
+            mTextureHeight = frame.height
+        }
+
+        fun updateTextures(frame: Frame) {
+            val width = frame.width
+            val height = frame.height
+            val half_width = width + 1 shr 1
+            val half_height = height + 1 shr 1
+            val y_size = width * height
+            val uv_size = half_width * half_height
+            val bb = frame.buffer
+            // If we are reusing this frame, make sure we reset position and
+            // limit
+            bb.clear()
+            if (bb.remaining() == y_size + uv_size * 2) {
+                bb.position(0)
+                GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1)
+                GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1)
+                GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[0])
+                GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width,
+                        height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE,
+                        bb)
+                bb.position(y_size)
+                GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[1])
+                GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
+                        half_width, half_height, GLES20.GL_LUMINANCE,
+                        GLES20.GL_UNSIGNED_BYTE, bb)
+                bb.position(y_size + uv_size)
+                GLES20.glActiveTexture(GLES20.GL_TEXTURE2)
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[2])
+                GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
+                        half_width, half_height, GLES20.GL_LUMINANCE,
+                        GLES20.GL_UNSIGNED_BYTE, bb)
+            } else {
+                mTextureWidth = 0
+                mTextureHeight = 0
+            }
+        }
+
+        override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
+            GLES20.glViewport(0, 0, width, height)
+            mViewportWidth = width
+            mViewportHeight = height
+        }
+
+        var metadataListener: DynamicVideoRendererMetadataListener? = null
+        override fun onDrawFrame(gl: GL10) {
+            gl.glClearColor(0f, 0f, 0f, 0f)
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
+            mFrameLock.lock()
+            if (mCurrentFrame != null && !mVideoDisabled) {
+                GLES20.glUseProgram(mProgram)
+                if (mTextureWidth != mCurrentFrame!!.width
+                        || mTextureHeight != mCurrentFrame!!.height) {
+                    setupTextures(mCurrentFrame!!)
+                }
+                updateTextures(mCurrentFrame!!)
+                Matrix.setIdentityM(mScaleMatrix, 0)
+                var scaleX = 1.0f
+                var scaleY = 1.0f
+                val ratio = (mCurrentFrame!!.width.toFloat()
+                        / mCurrentFrame!!.height)
+                val vratio = mViewportWidth.toFloat() / mViewportHeight
+                if (mVideoFitEnabled) {
+                    if (ratio > vratio) {
+                        scaleY = vratio / ratio
+                    } else {
+                        scaleX = ratio / vratio
+                    }
+                } else {
+                    if (ratio < vratio) {
+                        scaleY = vratio / ratio
+                    } else {
+                        scaleX = ratio / vratio
+                    }
+                }
+                Matrix.scaleM(mScaleMatrix, 0,
+                        scaleX * if (mCurrentFrame!!.isMirroredX) -1.0f else 1.0f,
+                        scaleY, 1f)
+                metadataListener?.onMetadataReady(mCurrentFrame!!.metadata)
+                val mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,
+                        "uMVPMatrix")
+                GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false,
+                        mScaleMatrix, 0)
+                enableThumbnailCircle(requestEnableThumbnailCircle)
+                GLES20.glDrawElements(GLES20.GL_TRIANGLES, mVertexIndex.size,
+                        GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer)
+            } else {
+                //black frame when video is disabled
+                gl.glClearColor(0f, 0f, 0f, 1f)
+                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
+            }
+            mFrameLock.unlock()
+        }
+
+        fun displayFrame(frame: Frame?) {
+            mFrameLock.lock()
+            if (mCurrentFrame != null) {
+                mCurrentFrame!!.recycle()
+            }
+            mCurrentFrame = frame
+            mFrameLock.unlock()
+        }
+
+        fun disableVideo(b: Boolean) {
+            mFrameLock.lock()
+            mVideoDisabled = b
+            if (mVideoDisabled) {
+                if (mCurrentFrame != null) {
+                    mCurrentFrame!!.recycle()
+                }
+                mCurrentFrame = null
+            }
+            mFrameLock.unlock()
+        }
+
+        fun enableVideoFit(enableVideoFit: Boolean) {
+            mVideoFitEnabled = enableVideoFit
+        }
+
+        companion object {
+            // number of coordinates per vertex in this array
+            const val COORDS_PER_VERTEX = 3
+            const val TEXTURECOORDS_PER_VERTEX = 2
+            var mXYZCoords = floatArrayOf(
+                    -1.0f, 1.0f, 0.0f,  // top left
+                    -1.0f, -1.0f, 0.0f,  // bottom left
+                    1.0f, -1.0f, 0.0f,  // bottom right
+                    1.0f, 1.0f, 0.0f // top right
+            )
+            var mUVCoords = floatArrayOf(0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f)
+            fun initializeTexture(name: Int, id: Int, width: Int, height: Int) {
+                GLES20.glActiveTexture(name)
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id)
+                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                        GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST.toFloat())
+                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                        GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR.toFloat())
+                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                        GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE.toFloat())
+                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                        GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE.toFloat())
+                GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
+                        width, height, 0, GLES20.GL_LUMINANCE,
+                        GLES20.GL_UNSIGNED_BYTE, null)
+            }
+
+            fun loadShader(type: Int, shaderCode: String?): Int {
+                val shader = GLES20.glCreateShader(type)
+                GLES20.glShaderSource(shader, shaderCode)
+                GLES20.glCompileShader(shader)
+                return shader
+            }
+        }
+
+        init {
+            val bb = ByteBuffer.allocateDirect(mXYZCoords.size * 4)
+            bb.order(ByteOrder.nativeOrder())
+            mVertexBuffer = bb.asFloatBuffer()
+            mVertexBuffer.put(mXYZCoords)
+            mVertexBuffer.position(0)
+            val tb = ByteBuffer.allocateDirect(mUVCoords.size * 4)
+            tb.order(ByteOrder.nativeOrder())
+            mTextureBuffer = tb.asFloatBuffer()
+            mTextureBuffer.put(mUVCoords)
+            mTextureBuffer.position(0)
+            val dlb = ByteBuffer.allocateDirect(mVertexIndex.size * 2)
+            dlb.order(ByteOrder.nativeOrder())
+            mDrawListBuffer = dlb.asShortBuffer()
+            mDrawListBuffer.put(mVertexIndex)
+            mDrawListBuffer.position(0)
+        }
+    }
+
+    override fun onFrame(frame: Frame) {
+        mRenderer.displayFrame(frame)
+        mView.requestRender()
+    }
+
+    override fun setStyle(key: String, value: String) {
+        if (STYLE_VIDEO_SCALE == key) {
+            if (STYLE_VIDEO_FIT == value) {
+                mRenderer.enableVideoFit(true)
+            } else if (STYLE_VIDEO_FILL == value) {
+                mRenderer.enableVideoFit(false)
+            }
+        }
+    }
+
+    override fun onVideoPropertiesChanged(videoEnabled: Boolean) {
+        mRenderer.disableVideo(!videoEnabled)
+    }
+
+    override fun getView(): View {
+        return mView
+    }
+
+    override fun onPause() {
+        mView.onPause()
+    }
+
+    override fun onResume() {
+        mView.onResume()
+    }
+
+    companion object {
+        private const val THUMBNAIL_SIZE = 90 //in dp
+    }
+
+    init {
+        mView.setEGLContextClientVersion(2)
+        mView.setEGLConfigChooser(8, 8, 8, 8, 16, 0)
+        mView.holder.setFormat(PixelFormat.TRANSLUCENT)
+        mRenderer = MyRenderer()
+        mView.setRenderer(mRenderer)
+        mView.renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
+    }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/hmg/hmgDr/util/ThumbnailCircleVideoRenderer.kt b/android/app/src/main/kotlin/com/hmg/hmgDr/util/ThumbnailCircleVideoRenderer.kt
new file mode 100644
index 00000000..b9b5a245
--- /dev/null
+++ b/android/app/src/main/kotlin/com/hmg/hmgDr/util/ThumbnailCircleVideoRenderer.kt
@@ -0,0 +1,357 @@
+package com.hmg.hmgDr.util
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.PixelFormat
+import android.opengl.GLES20
+import android.opengl.GLSurfaceView
+import android.opengl.Matrix
+import android.view.View
+import com.opentok.android.BaseVideoRenderer
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+import java.nio.FloatBuffer
+import java.nio.ShortBuffer
+import java.util.concurrent.locks.ReentrantLock
+import javax.microedition.khronos.egl.EGLConfig
+import javax.microedition.khronos.opengles.GL10
+
+
+class ThumbnailCircleVideoRenderer(private val mContext: Context) : BaseVideoRenderer() {
+    private val mView: GLSurfaceView = GLSurfaceView(mContext)
+    private val mRenderer: MyRenderer
+
+    interface ThumbnailCircleVideoRendererMetadataListener {
+        fun onMetadataReady(metadata: ByteArray?)
+    }
+
+    fun setThumbnailCircleVideoRendererMetadataListener(metadataListener: ThumbnailCircleVideoRendererMetadataListener?) {
+        mRenderer.metadataListener = metadataListener
+    }
+
+    internal class MyRenderer : GLSurfaceView.Renderer {
+        var mTextureIds = IntArray(3)
+        var mScaleMatrix = FloatArray(16)
+        private val mVertexBuffer: FloatBuffer
+        private val mTextureBuffer: FloatBuffer
+        private val mDrawListBuffer: ShortBuffer
+        var mVideoFitEnabled = true
+        var mVideoDisabled = false
+        private val mVertexIndex = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw
+
+        // vertices
+        private val vertexShaderCode = """uniform mat4 uMVPMatrix;attribute vec4 aPosition;
+attribute vec2 aTextureCoord;
+varying vec2 vTextureCoord;
+void main() {
+  gl_Position = uMVPMatrix * aPosition;
+  vTextureCoord = aTextureCoord;
+}
+"""
+        private val fragmentShaderCode = """precision mediump float;
+uniform sampler2D Ytex;
+uniform sampler2D Utex,Vtex;
+uniform vec2 radiusDp;
+varying vec2 vTextureCoord;
+void main(void) {
+  float nx,ny,r,g,b,y,u,v;
+  mediump vec4 txl,ux,vx;  nx=vTextureCoord[0];
+  ny=vTextureCoord[1];
+  y=texture2D(Ytex,vec2(nx,ny)).r;
+  u=texture2D(Utex,vec2(nx,ny)).r;
+  v=texture2D(Vtex,vec2(nx,ny)).r;
+  y=1.1643*(y-0.0625);
+  u=u-0.5;
+  v=v-0.5;
+  r=y+1.5958*v;
+  g=y-0.39173*u-0.81290*v;
+  b=y+2.017*u;
+  float radius = 0.5;
+  vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);
+  vec4 color1 = vec4(r, g, b, 1.0);
+  vec2 st = (gl_FragCoord.xy/radiusDp.xy);  float dist = radius - distance(st,vec2(0.5));
+  float t = 1.0;
+  if (dist < 0.0) t = 0.0;
+  gl_FragColor = mix(color0, color1, t);
+}
+"""
+        var mFrameLock = ReentrantLock()
+        var mCurrentFrame: Frame? = null
+        private var mProgram = 0
+        private var mTextureWidth = 0
+        private var mTextureHeight = 0
+        private var mViewportWidth = 0
+        private var mViewportHeight = 0
+        override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
+            gl.glClearColor(0f, 0f, 0f, 1f)
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
+            val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
+                    vertexShaderCode)
+            val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
+                    fragmentShaderCode)
+            mProgram = GLES20.glCreateProgram() // create empty OpenGL ES
+            // Program
+            GLES20.glAttachShader(mProgram, vertexShader) // add the vertex
+            // shader to program
+            GLES20.glAttachShader(mProgram, fragmentShader) // add the fragment
+            // shader to
+            // program
+            GLES20.glLinkProgram(mProgram)
+            val positionHandle = GLES20.glGetAttribLocation(mProgram,
+                    "aPosition")
+            val textureHandle = GLES20.glGetAttribLocation(mProgram,
+                    "aTextureCoord")
+            GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
+                    GLES20.GL_FLOAT, false, COORDS_PER_VERTEX * 4,
+                    mVertexBuffer)
+            GLES20.glEnableVertexAttribArray(positionHandle)
+            GLES20.glVertexAttribPointer(textureHandle,
+                    TEXTURECOORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
+                    TEXTURECOORDS_PER_VERTEX * 4, mTextureBuffer)
+            GLES20.glEnableVertexAttribArray(textureHandle)
+            GLES20.glUseProgram(mProgram)
+            var i = GLES20.glGetUniformLocation(mProgram, "Ytex")
+            GLES20.glUniform1i(i, 0) /* Bind Ytex to texture unit 0 */
+            i = GLES20.glGetUniformLocation(mProgram, "Utex")
+            GLES20.glUniform1i(i, 1) /* Bind Utex to texture unit 1 */
+            i = GLES20.glGetUniformLocation(mProgram, "Vtex")
+            GLES20.glUniform1i(i, 2) /* Bind Vtex to texture unit 2 */
+            val radiusDpLocation = GLES20.glGetUniformLocation(mProgram, "radiusDp")
+            val radiusDp = (Resources.getSystem().displayMetrics.density * THUMBNAIL_SIZE).toInt()
+            GLES20.glUniform2f(radiusDpLocation, radiusDp.toFloat(), radiusDp.toFloat())
+            mTextureWidth = 0
+            mTextureHeight = 0
+        }
+
+        fun setupTextures(frame: Frame) {
+            if (mTextureIds[0] != 0) {
+                GLES20.glDeleteTextures(3, mTextureIds, 0)
+            }
+            GLES20.glGenTextures(3, mTextureIds, 0)
+            val w = frame.width
+            val h = frame.height
+            val hw = w + 1 shr 1
+            val hh = h + 1 shr 1
+            initializeTexture(GLES20.GL_TEXTURE0, mTextureIds[0], w, h)
+            initializeTexture(GLES20.GL_TEXTURE1, mTextureIds[1], hw, hh)
+            initializeTexture(GLES20.GL_TEXTURE2, mTextureIds[2], hw, hh)
+            mTextureWidth = frame.width
+            mTextureHeight = frame.height
+        }
+
+        fun updateTextures(frame: Frame) {
+            val width = frame.width
+            val height = frame.height
+            val half_width = width + 1 shr 1
+            val half_height = height + 1 shr 1
+            val y_size = width * height
+            val uv_size = half_width * half_height
+            val bb = frame.buffer
+            // If we are reusing this frame, make sure we reset position and
+            // limit
+            bb.clear()
+            if (bb.remaining() == y_size + uv_size * 2) {
+                bb.position(0)
+                GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1)
+                GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1)
+                GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[0])
+                GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width,
+                        height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE,
+                        bb)
+                bb.position(y_size)
+                GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[1])
+                GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
+                        half_width, half_height, GLES20.GL_LUMINANCE,
+                        GLES20.GL_UNSIGNED_BYTE, bb)
+                bb.position(y_size + uv_size)
+                GLES20.glActiveTexture(GLES20.GL_TEXTURE2)
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[2])
+                GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
+                        half_width, half_height, GLES20.GL_LUMINANCE,
+                        GLES20.GL_UNSIGNED_BYTE, bb)
+            } else {
+                mTextureWidth = 0
+                mTextureHeight = 0
+            }
+        }
+
+        override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
+            GLES20.glViewport(0, 0, width, height)
+            mViewportWidth = width
+            mViewportHeight = height
+        }
+
+        var metadataListener: ThumbnailCircleVideoRendererMetadataListener? = null
+        override fun onDrawFrame(gl: GL10) {
+            gl.glClearColor(0f, 0f, 0f, 0f)
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
+            mFrameLock.lock()
+            if (mCurrentFrame != null && !mVideoDisabled) {
+                GLES20.glUseProgram(mProgram)
+                if (mTextureWidth != mCurrentFrame!!.width
+                        || mTextureHeight != mCurrentFrame!!.height) {
+                    setupTextures(mCurrentFrame!!)
+                }
+                updateTextures(mCurrentFrame!!)
+                Matrix.setIdentityM(mScaleMatrix, 0)
+                var scaleX = 1.0f
+                var scaleY = 1.0f
+                val ratio = (mCurrentFrame!!.width.toFloat()
+                        / mCurrentFrame!!.height)
+                val vratio = mViewportWidth.toFloat() / mViewportHeight
+                if (mVideoFitEnabled) {
+                    if (ratio > vratio) {
+                        scaleY = vratio / ratio
+                    } else {
+                        scaleX = ratio / vratio
+                    }
+                } else {
+                    if (ratio < vratio) {
+                        scaleY = vratio / ratio
+                    } else {
+                        scaleX = ratio / vratio
+                    }
+                }
+                Matrix.scaleM(mScaleMatrix, 0,
+                        scaleX * if (mCurrentFrame!!.isMirroredX) -1.0f else 1.0f,
+                        scaleY, 1f)
+                metadataListener?.onMetadataReady(mCurrentFrame!!.metadata)
+                val mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,
+                        "uMVPMatrix")
+                GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false,
+                        mScaleMatrix, 0)
+                GLES20.glDrawElements(GLES20.GL_TRIANGLES, mVertexIndex.size,
+                        GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer)
+            } else {
+                //black frame when video is disabled
+                gl.glClearColor(0f, 0f, 0f, 1f)
+                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
+            }
+            mFrameLock.unlock()
+        }
+
+        fun displayFrame(frame: Frame?) {
+            mFrameLock.lock()
+            if (mCurrentFrame != null) {
+                mCurrentFrame!!.recycle()
+            }
+            mCurrentFrame = frame
+            mFrameLock.unlock()
+        }
+
+        fun disableVideo(b: Boolean) {
+            mFrameLock.lock()
+            mVideoDisabled = b
+            if (mVideoDisabled) {
+                if (mCurrentFrame != null) {
+                    mCurrentFrame!!.recycle()
+                }
+                mCurrentFrame = null
+            }
+            mFrameLock.unlock()
+        }
+
+        fun enableVideoFit(enableVideoFit: Boolean) {
+            mVideoFitEnabled = enableVideoFit
+        }
+
+        companion object {
+            // number of coordinates per vertex in this array
+            const val COORDS_PER_VERTEX = 3
+            const val TEXTURECOORDS_PER_VERTEX = 2
+            var mXYZCoords = floatArrayOf(
+                    -1.0f, 1.0f, 0.0f,  // top left
+                    -1.0f, -1.0f, 0.0f,  // bottom left
+                    1.0f, -1.0f, 0.0f,  // bottom right
+                    1.0f, 1.0f, 0.0f // top right
+            )
+            var mUVCoords = floatArrayOf(0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f)
+            fun initializeTexture(name: Int, id: Int, width: Int, height: Int) {
+                GLES20.glActiveTexture(name)
+                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id)
+                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                        GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST.toFloat())
+                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                        GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR.toFloat())
+                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                        GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE.toFloat())
+                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                        GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE.toFloat())
+                GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
+                        width, height, 0, GLES20.GL_LUMINANCE,
+                        GLES20.GL_UNSIGNED_BYTE, null)
+            }
+
+            fun loadShader(type: Int, shaderCode: String?): Int {
+                val shader = GLES20.glCreateShader(type)
+                GLES20.glShaderSource(shader, shaderCode)
+                GLES20.glCompileShader(shader)
+                return shader
+            }
+        }
+
+        init {
+            val bb = ByteBuffer.allocateDirect(mXYZCoords.size * 4)
+            bb.order(ByteOrder.nativeOrder())
+            mVertexBuffer = bb.asFloatBuffer()
+            mVertexBuffer.put(mXYZCoords)
+            mVertexBuffer.position(0)
+            val tb = ByteBuffer.allocateDirect(mUVCoords.size * 4)
+            tb.order(ByteOrder.nativeOrder())
+            mTextureBuffer = tb.asFloatBuffer()
+            mTextureBuffer.put(mUVCoords)
+            mTextureBuffer.position(0)
+            val dlb = ByteBuffer.allocateDirect(mVertexIndex.size * 2)
+            dlb.order(ByteOrder.nativeOrder())
+            mDrawListBuffer = dlb.asShortBuffer()
+            mDrawListBuffer.put(mVertexIndex)
+            mDrawListBuffer.position(0)
+        }
+    }
+
+    override fun onFrame(frame: Frame) {
+        mRenderer.displayFrame(frame)
+        mView.requestRender()
+    }
+
+    override fun setStyle(key: String, value: String) {
+        if (STYLE_VIDEO_SCALE == key) {
+            if (STYLE_VIDEO_FIT == value) {
+                mRenderer.enableVideoFit(true)
+            } else if (STYLE_VIDEO_FILL == value) {
+                mRenderer.enableVideoFit(false)
+            }
+        }
+    }
+
+    override fun onVideoPropertiesChanged(videoEnabled: Boolean) {
+        mRenderer.disableVideo(!videoEnabled)
+    }
+
+    override fun getView(): View {
+        return mView
+    }
+
+    override fun onPause() {
+        mView.onPause()
+    }
+
+    override fun onResume() {
+        mView.onResume()
+    }
+
+    companion object {
+        private const val THUMBNAIL_SIZE = 90 //in dp
+    }
+
+    init {
+        mView.setEGLContextClientVersion(2)
+        mView.setEGLConfigChooser(8, 8, 8, 8, 16, 0)
+        mView.holder.setFormat(PixelFormat.TRANSLUCENT)
+        mRenderer = MyRenderer()
+        mView.setRenderer(mRenderer)
+        mView.renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
+    }
+}
diff --git a/android/app/src/main/res/layout/activity_video_call.xml b/android/app/src/main/res/layout/activity_video_call.xml
index a7470da3..a54e57b3 100644
--- a/android/app/src/main/res/layout/activity_video_call.xml
+++ b/android/app/src/main/res/layout/activity_video_call.xml
@@ -97,8 +97,7 @@
             android:layout_alignParentTop="true"
             android:layout_alignParentEnd="true"
             android:layout_marginTop="@dimen/local_preview_margin_top"
-            android:layout_marginEnd="@dimen/local_preview_margin_top"
-            android:background="@color/localBackground">
+            android:layout_marginEnd="@dimen/local_preview_margin_top">
 
             
         
 
+        
+