opentok / opentok-android-sdk-samples

Sample applications illustrating best practices using OpenTok Android SDK.
https://tokbox.com/developer/sdks/android/
MIT License
212 stars 169 forks source link

Black stream when switching between Publishers after cycleCamera #503

Closed Doctoror closed 7 months ago

Doctoror commented 7 months ago

Describe the bug Publisher produces black stream when switching between Publishers after cycleCamera.

To Reproduce Steps to reproduce the behavior:

  1. It seems to be reproducible on Samsung S23 or Samsung S23 Ultra but it's hard to reproduce on other devices
  2. Run the minimal reproducible example attached
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import com.opentok.android.Publisher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {

    private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
            if (isGranted) {
                onCameraPermissionGranted()
            } else {
                Toast.makeText(this, "Cannot run without permission", Toast.LENGTH_LONG).show()
            }
        }

    private lateinit var publisher1: Publisher
    private lateinit var publisher2: Publisher

    private lateinit var container1: ViewGroup
    private lateinit var container2: ViewGroup

    private var job: Job? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        container1 = findViewById(R.id.container1)
        container2 = findViewById(R.id.container2)
    }

    override fun onResume() {
        super.onResume()
        if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            onCameraPermissionGranted()
        } else {
            requestPermissionLauncher.launch(Manifest.permission.CAMERA)
        }
    }

    override fun onPause() {
        super.onPause()
        job?.cancel()
        job = null
    }

    private fun onCameraPermissionGranted() {
        if (!::publisher1.isInitialized) {

            publisher1 = Publisher.Builder(this).build()
            publisher1.publishVideo = false

            publisher2 = Publisher.Builder(this).build()
            publisher2.publishVideo = false

            container1.addView(publisher1.view)
            container2.addView(publisher2.view)
        }

        runJob()
    }

    private fun runJob() {
        job = GlobalScope.launch(Dispatchers.Main) {
            publisher1.publishVideo = true
            delay(2000)

            publisher1.cycleCamera()
            delay(2000)

            publisher1.publishVideo = false
            delay(2000)

            publisher2.publishVideo = true
            delay(2000)

            publisher2.publishVideo = false
            publisher1.publishVideo = true
        }
    }
}

It is not reproducible if you add delay between switching videos between publishers (last 2 lines)

publisher2.publishVideo = false
delay(2000)
publisher1.publishVideo = true

layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/container1"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <FrameLayout
        android:id="@+id/container2"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>

Expected behavior publisher1 stream is not black

Screenshots Video recording of minimum reproducible sample from above: Recording.mp4

Device (please compete the following information):

Additional context Possible solutions:

v-kpheng commented 7 months ago

@Doctoror, I'm going to close this, since you're working with Support: https://jira.vonage.com/browse/VIDCS-2100.