Finish Android tutorial
This commit is contained in:
parent
495f780fa9
commit
c3b9d3c5f8
@ -19,7 +19,7 @@ class MainActivity : AppCompatActivity() {
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.participantName.setText("Participant %d".format((1..100).random()))
|
||||
binding.participantName.setText("Participant%d".format((1..100).random()))
|
||||
|
||||
binding.joinButton.setOnClickListener {
|
||||
navigateToRoomLayoutActivity()
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
package io.openvidu.android
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.livekit.android.room.Room
|
||||
import io.openvidu.android.databinding.ParticipantItemBinding
|
||||
|
||||
class ParticipantAdapter(private val participantTracks: List<TrackInfo>, private val room: Room) :
|
||||
RecyclerView.Adapter<ParticipantViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ParticipantViewHolder =
|
||||
ParticipantViewHolder(
|
||||
ParticipantItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: ParticipantViewHolder, position: Int) {
|
||||
val trackInfo = participantTracks[position]
|
||||
holder.render(trackInfo, room)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = participantTracks.size
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package io.openvidu.android
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.livekit.android.room.Room
|
||||
import io.openvidu.android.databinding.ParticipantItemBinding
|
||||
|
||||
class ParticipantViewHolder(private val binding: ParticipantItemBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
private var used = false
|
||||
|
||||
fun render(trackInfo: TrackInfo, room: Room) {
|
||||
val participantIdentity = if (trackInfo.isLocal) {
|
||||
trackInfo.participantIdentity + " (You)"
|
||||
} else {
|
||||
trackInfo.participantIdentity
|
||||
}
|
||||
|
||||
binding.identity.text = participantIdentity
|
||||
|
||||
if (!used) {
|
||||
room.initVideoRenderer(binding.renderer)
|
||||
used = true
|
||||
}
|
||||
|
||||
trackInfo.track.addRenderer(binding.renderer)
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.engine.cio.CIO
|
||||
@ -23,17 +24,26 @@ import io.livekit.android.events.RoomEvent
|
||||
import io.livekit.android.events.collect
|
||||
import io.livekit.android.room.Room
|
||||
import io.livekit.android.room.track.VideoTrack
|
||||
import io.livekit.android.util.flow
|
||||
import io.openvidu.android.databinding.ActivityRoomLayoutBinding
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
data class TrackInfo(
|
||||
val track: VideoTrack,
|
||||
val participantIdentity: String,
|
||||
val isLocal: Boolean = false
|
||||
)
|
||||
|
||||
class RoomLayoutActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityRoomLayoutBinding
|
||||
private lateinit var participantAdapter: ParticipantAdapter
|
||||
|
||||
private lateinit var APPLICATION_SERVER_URL: String
|
||||
private lateinit var LIVEKIT_URL: String
|
||||
|
||||
private lateinit var room: Room
|
||||
private val participantTracks: MutableList<TrackInfo> = mutableListOf()
|
||||
|
||||
private val client = HttpClient(CIO) {
|
||||
expectSuccess = true
|
||||
@ -47,22 +57,33 @@ class RoomLayoutActivity : AppCompatActivity() {
|
||||
binding = ActivityRoomLayoutBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
binding.leaveButton.setOnClickListener {
|
||||
leaveRoom()
|
||||
}
|
||||
|
||||
APPLICATION_SERVER_URL = intent.getStringExtra("serverUrl") ?: ""
|
||||
LIVEKIT_URL = intent.getStringExtra("livekitUrl") ?: ""
|
||||
|
||||
// Create Room object.
|
||||
room = LiveKit.create(applicationContext)
|
||||
|
||||
// Setup the video renderer
|
||||
room.initVideoRenderer(binding.renderer)
|
||||
|
||||
initRecyclerView()
|
||||
requestNeededPermissions { connectToRoom() }
|
||||
}
|
||||
|
||||
private fun initRecyclerView() {
|
||||
participantAdapter = ParticipantAdapter(participantTracks, room)
|
||||
binding.participants.layoutManager = LinearLayoutManager(this)
|
||||
binding.participants.adapter = participantAdapter
|
||||
}
|
||||
|
||||
private fun connectToRoom() {
|
||||
val participantName = intent.getStringExtra("participantName") ?: "Participant 1"
|
||||
val roomName = intent.getStringExtra("roomName") ?: "Test Room"
|
||||
|
||||
binding.roomName.text = roomName
|
||||
|
||||
lifecycleScope.launch {
|
||||
// Setup event handling.
|
||||
launch {
|
||||
@ -86,6 +107,24 @@ class RoomLayoutActivity : AppCompatActivity() {
|
||||
val localParticipant = room.localParticipant
|
||||
localParticipant.setMicrophoneEnabled(true)
|
||||
localParticipant.setCameraEnabled(true)
|
||||
|
||||
// Add local video track to the participantTracks list.
|
||||
launch {
|
||||
localParticipant::videoTrackPublications.flow
|
||||
.collect { publications ->
|
||||
val videoTrack = publications.firstOrNull()?.second as? VideoTrack
|
||||
|
||||
if (videoTrack != null) {
|
||||
participantTracks.add(
|
||||
0,
|
||||
TrackInfo(videoTrack, participantName, true)
|
||||
)
|
||||
participantAdapter.notifyItemInserted(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.loader.visibility = View.GONE
|
||||
} catch (e: Exception) {
|
||||
println("There was an error connecting to the room: ${e.message}")
|
||||
Toast.makeText(this@RoomLayoutActivity, "Failed to join room", Toast.LENGTH_SHORT)
|
||||
@ -99,26 +138,22 @@ class RoomLayoutActivity : AppCompatActivity() {
|
||||
val track = event.track
|
||||
|
||||
if (track is VideoTrack) {
|
||||
attachVideo(track)
|
||||
participantTracks.add(TrackInfo(track, event.participant.identity!!.value))
|
||||
participantAdapter.notifyItemInserted(participantTracks.size - 1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachVideo(videoTrack: VideoTrack) {
|
||||
videoTrack.addRenderer(binding.renderer)
|
||||
binding.progress.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun onTrackUnsubscribed(event: RoomEvent.TrackUnsubscribed) {
|
||||
val track = event.track
|
||||
|
||||
if (track is VideoTrack) {
|
||||
detachVideo(track)
|
||||
}
|
||||
}
|
||||
val index = participantTracks.indexOfFirst { it.track.sid == track.sid }
|
||||
|
||||
private fun detachVideo(videoTrack: VideoTrack) {
|
||||
videoTrack.removeRenderer(binding.renderer)
|
||||
binding.progress.visibility = View.VISIBLE
|
||||
if (index != -1) {
|
||||
participantTracks.removeAt(index)
|
||||
participantAdapter.notifyItemRemoved(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun leaveRoom() {
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/participantBackground" />
|
||||
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/identityBackground" />
|
||||
|
||||
<corners
|
||||
android:bottomRightRadius="5dp"
|
||||
android:topLeftRadius="5dp" />
|
||||
</shape>
|
||||
@ -49,7 +49,8 @@
|
||||
android:inputType="text"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/participantLabel" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/participantLabel"
|
||||
tools:text="Participant1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomLabel"
|
||||
|
||||
@ -1,19 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="20dp"
|
||||
tools:context=".RoomLayoutActivity">
|
||||
|
||||
<io.livekit.android.renderer.SurfaceViewRenderer
|
||||
android:id="@+id/renderer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
<TextView
|
||||
android:id="@+id/roomName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center" />
|
||||
android:layout_marginStart="16dp"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Test Room" />
|
||||
|
||||
</FrameLayout>
|
||||
<Button
|
||||
android:id="@+id/leaveButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:backgroundTint="@color/leaveRoomButton"
|
||||
android:text="@string/leave_room"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loader"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/participants"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomName" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/rounded_corner_background"
|
||||
android:clipToOutline="true">
|
||||
|
||||
<io.livekit.android.renderer.TextureViewRenderer
|
||||
android:id="@+id/renderer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="3:4"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/identity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/rounded_corner_text"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:textColor="@color/textColor"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Participant1" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -6,4 +6,7 @@
|
||||
<color name="colorAccent">#0087A9</color>
|
||||
<color name="backgroundColor">#4D4D4D</color>
|
||||
<color name="textColor">#4D4D4D</color>
|
||||
<color name="leaveRoomButton">#F24949</color>
|
||||
<color name="participantBackground">#2F2F2F</color>
|
||||
<color name="identityBackground">#B8B8B8</color>
|
||||
</resources>
|
||||
@ -8,4 +8,5 @@
|
||||
<string name="application_server_url">Application Server URL</string>
|
||||
<string name="livekit_url">LiveKit URL</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="leave_room">Leave Room</string>
|
||||
</resources>
|
||||
Loading…
x
Reference in New Issue
Block a user