ConnectyCube / android-messenger-app

Chat and voice / video calling app using ConnectyCube
https://connectycube.com
Apache License 2.0
52 stars 23 forks source link

Connectycube android VideoChatWebRTCSignalingManager not getting assigned #97

Closed archidvignesh closed 3 years ago

archidvignesh commented 3 years ago

So I followed the instruction in the documentation. I am building a one to one video calling app. What I have done is, as soon as the fragment is created:

  1. As soon as activity is created, I initialize connecty cube with admin credentials
  2. As soon as fragment is created, I check if user exists using a view model (view model is activity scoped, all below steps done in view model)
  3. If user exists, then I perform a login to refresh the session
  4. As soon as user is logged in, I setup the connectycube chat service as it was mentioned that you need chat to signal
  5. Then I log into chat service using user credentials
  6. Now I am told to add web rtc video signaling manager to Chat service instance (This is where the problem is)
  7. After signalling manager I prepare to process calls

Unfortunately, the callback is not being called when I try to add the signalling manager callback at step 5. I seem to have done everything right by the documentation. Here is the code outlined in steps

Step 1: Here is how the activity begins


class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //Any app delegate initializations can be done here
        initializeConnectyCube()

        //setup view model
        val application = this.application
        val viewModelFactory = MainViewModelFactory(PreferenceManager.getDefaultSharedPreferences(this), application)
        viewModel = ViewModelProvider(this, viewModelFactory).get(MainViewModel::class.java)

        //setup UI - now the fragment functions start getting called
        setContentView(R.layout.activity_main)
    }

    private fun initializeConnectyCube() {
        ConnectycubeSettings.getInstance().init(applicationContext, APP_ID, AUTH_KEY, AUTH_SECRET)
        ConnectycubeSettings.getInstance().accountKey = ACCOUNT_KEY
    }

    override fun onDestroy() {
        super.onDestroy()
        viewModel.releaseResources(true)
    }
}

After this activity is set, it hosts HomeFragment. Here is the code for HomeFragment. HomeFragment refers to the activity scoped view model which is MainViewModel as seen above

class HomeFragment : Fragment() {
    private lateinit var viewModel: MainViewModel
    private lateinit var binding: FragmentHomeBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        //Create view model first
        val application = this.requireActivity().application
        val viewModelFactory = MainViewModelFactory(PreferenceManager.getDefaultSharedPreferences(this.activity), application)
        viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MainViewModel::class.java)

        //Create binding
        binding = FragmentHomeBinding.inflate(layoutInflater)
        binding.logoutButton.setOnClickListener {
            viewModel.handleLogout()
        }

        binding.connectButton.setOnClickListener {
            val userIdText = binding.editText.text.toString()
            if (userIdText.isNotEmpty()) {
                viewModel.handleConnect(userIdText)
            }
        }

        viewModel.checkIfUserExists()
        return binding.root
    }
}

Here is how check if user exists call from HomeFragment works in view model

class MainViewModel(private val sharedPreferences: SharedPreferences, application: Application): AndroidViewModel(application), RTCClientSessionCallbacks, RTCClientVideoTracksCallback<RTCSession> {

    fun checkIfUserExists() {
        val userEmail = sharedPreferences.getString(UDLoginUserEmail, null)
        val userPassword = sharedPreferences.getString(UDLoginUserPassword, null)

        if (userEmail.isNullOrEmpty() || userPassword.isNullOrEmpty()) {
            _isUserLoggedOut.value = true
        } else {
            loginUserAndRefreshSession()
            Log.d("MainViewModel", "User exists, performing login and session refresh")
        }
    }

    private fun loginUserAndRefreshSession() {
        val userEmail = sharedPreferences.getString(UDLoginUserEmail, null)
        val userPassword = sharedPreferences.getString(UDLoginUserPassword, null)

        ConnectycubeUsers.signInByEmail(userEmail, userPassword).performAsync(object: EntityCallback<ConnectycubeUser> {
            override fun onSuccess(p0: ConnectycubeUser?, p1: Bundle?) {
                val userId = p0?.id ?: 0
                val userName = p0?.fullName ?: ""
                _nameText.value = userName
                setupConnectyCubeChatService(userId, userPassword ?: "")
                Log.d("MainViewModel", "Login success. Setting up chat service")
            }

            override fun onError(p0: ResponseException?) {
                _errorString.value = p0?.localizedMessage ?: ""
            }
        })
    }

    private fun setupConnectyCubeChatService(userId: Int, userPassword: String) {
        val chatServiceConfigurationBuilder = ConnectycubeChatService.ConfigurationBuilder().apply {
            socketTimeout = 60
            isKeepAlive = true
            isUseTls = true
        }

        ConnectycubeChatService.setConnectionFabric(TcpChatConnectionFabric(chatServiceConfigurationBuilder))
        val connectyCubeUser = ConnectycubeUser().apply {
            id = userId
            password = userPassword
        }

        ConnectycubeChatService.getInstance().login(connectyCubeUser, object: EntityCallback<Void?> {
            override fun onSuccess(p0: Void?, p1: Bundle?) {
                Log.d("MainViewModel", "Chat service setup. Performing call service")
                setupConnectyCubeCallService()
            }

            override fun onError(p0: ResponseException?) {
                _errorString.value = p0?.localizedMessage ?: ""
            }
        })
    }

    private fun setupConnectyCubeCallService() {
        Log.d("MainViewModel", "Starting call service")
        //-------------------------------------BELOW LINE DOES NOTHING -------------------
        //-------------------------------------BELOW LINE DOES NOTHING -------------------
        ConnectycubeChatService.getInstance().videoChatWebRTCSignalingManager.addSignalingManagerListener { p0, p1 ->
            if (!p1) {
                Log.d("MainViewModel", "Call service entered block")
                RTCClient.getInstance(getApplication<Application>().applicationContext).addSignaling(p0 as WebRTCSignaling)
                RTCClient.getInstance(this.getApplication<Application>().applicationContext).prepareToProcessCalls()
                RTCClient.getInstance(this.getApplication<Application>().applicationContext).addSessionCallbacksListener(this)
                _notificationText.value = "ConnectyCube ready"
                Log.d("MainViewModel", "Connectycube ready")
            }
        }
    }
}

class MainViewModelFactory(private val sharedPreferences: SharedPreferences, private val application: Application): ViewModelProvider.Factory {
    @Suppress("unchecked_cast")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            return MainViewModel(sharedPreferences, application) as T
        }
        throw IllegalArgumentException("Unknown class")
    }

As you can see in the view model code, I am getting stuck at the function setupConnectycubeCallService(). Nothing basically happens when I try to initialize video call using connecty cube chat

TatankaConCube commented 3 years ago

@archidvignesh 1 - why you init listeners in the addSignalingManagerListener but not as in our example? 2 - I didn't found the implementation for addSessionCallbacksListener, you set this there, but in your code this is a callback but not the MainViewModel.

please follow carefully our guides and be careful in your code

archidvignesh commented 3 years ago

@TatankaConCube Thanks for your response. Yes I think i have to fix what you have mentioned in point number 2. I have implemented the interface and maybe I made a mistake while using this. Will try it out

As for point 1 however, the below line in itself is not called

if (!createdLocally) {
}

I am not using a separate session manager class. I am just calling it once a fragment is created just to test calls. The callback is not fired at all. Even the if statement is not called when I try adding break points. This is from connectycube official documentation that states I can call the below line as soon as the activity is ready

ConnectycubeChatService.getInstance().videoChatWebRTCSignalingManager.addSignalingManagerListener()
TatankaConCube commented 3 years ago

No activity for a long time, so closing.