Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
xuning
/
livekitAndroidXuningTest
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
David Liu
2021-11-18 01:31:09 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
95c266dfe5b30f908caa62925f754736d2ab6f82
95c266df
1 parent
36384a67
sample app redesign
隐藏空白字符变更
内嵌
并排对比
正在显示
20 个修改的文件
包含
253 行增加
和
154 行删除
livekit-android-sdk/src/main/java/io/livekit/android/room/participant/LocalParticipant.kt
sample-app-common/src/main/java/io/livekit/android/sample/util/LiveDataExt.kt
sample-app-compose/src/main/res/drawable/baseline_cast_24.xml → sample-app-common/src/main/res/drawable/baseline_cast_24.xml
sample-app-compose/src/main/res/drawable/baseline_cast_connected_24.xml → sample-app-common/src/main/res/drawable/baseline_cast_connected_24.xml
sample-app-compose/src/main/res/drawable/outline_flip_camera_android_24.xml → sample-app-common/src/main/res/drawable/outline_flip_camera_android_24.xml
sample-app-compose/src/main/res/drawable/outline_mic_24.xml → sample-app-common/src/main/res/drawable/outline_mic_24.xml
sample-app-compose/src/main/res/drawable/outline_mic_off_24.xml → sample-app-common/src/main/res/drawable/outline_mic_off_24.xml
sample-app-compose/src/main/res/drawable/outline_videocam_24.xml → sample-app-common/src/main/res/drawable/outline_videocam_24.xml
sample-app-compose/src/main/res/drawable/outline_videocam_off_24.xml → sample-app-common/src/main/res/drawable/outline_videocam_off_24.xml
sample-app/src/main/java/io/livekit/android/sample/CallActivity.kt
sample-app/src/main/java/io/livekit/android/sample/CallViewModel.kt
sample-app/src/main/java/io/livekit/android/sample/ParticipantItem.kt
sample-app/src/main/res/drawable/ic_round_mic_24.xml
sample-app/src/main/res/drawable/ic_round_mic_off_24.xml
sample-app/src/main/res/drawable/ic_round_videocam_24.xml
sample-app/src/main/res/drawable/ic_round_videocam_off_24.xml
sample-app/src/main/res/layout/call_activity.xml
sample-app/src/main/res/layout/participant_item.xml
sample-app/src/main/res/values/dimens.xml
sample-app/src/main/res/values/styles.xml
livekit-android-sdk/src/main/java/io/livekit/android/room/participant/LocalParticipant.kt
查看文件 @
95c266d
...
...
@@ -108,16 +108,24 @@ internal constructor(
return super.getTrackPublicationByName(name) as? LocalTrackPublication
}
suspend fun setCameraEnabled(enabled: Boolean){
suspend fun setCameraEnabled(enabled: Boolean)
{
setTrackEnabled(Track.Source.CAMERA, enabled)
}
suspend fun setMicrophoneEnabled(enabled: Boolean){
suspend fun setMicrophoneEnabled(enabled: Boolean)
{
setTrackEnabled(Track.Source.MICROPHONE, enabled)
}
suspend fun setScreenShareEnabled(enabled: Boolean) {
setTrackEnabled(Track.Source.SCREEN_SHARE, enabled)
/**
* @param mediaProjectionPermissionResultData The resultData returned from launching
* [MediaProjectionManager.createScreenCaptureIntent()](https://developer.android.com/reference/android/media/projection/MediaProjectionManager#createScreenCaptureIntent()).
* @throws IllegalArgumentException if attempting to enable screenshare without [mediaProjectionPermissionResultData]
*/
suspend fun setScreenShareEnabled(
enabled: Boolean,
mediaProjectionPermissionResultData: Intent? = null
) {
setTrackEnabled(Track.Source.SCREEN_SHARE, enabled, mediaProjectionPermissionResultData)
}
private suspend fun setTrackEnabled(
...
...
sample-app-common/src/main/java/io/livekit/android/sample/util/LiveDataExt.kt
0 → 100644
查看文件 @
95c266d
package io.livekit.android.sample.util
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
fun <T> MutableLiveData<T>.hide(): LiveData<T> = this
\ No newline at end of file
...
...
sample-app-com
pose
/src/main/res/drawable/baseline_cast_24.xml → sample-app-com
mon
/src/main/res/drawable/baseline_cast_24.xml
查看文件 @
95c266d
sample-app-com
pose
/src/main/res/drawable/baseline_cast_connected_24.xml → sample-app-com
mon
/src/main/res/drawable/baseline_cast_connected_24.xml
查看文件 @
95c266d
sample-app-com
pose
/src/main/res/drawable/outline_flip_camera_android_24.xml → sample-app-com
mon
/src/main/res/drawable/outline_flip_camera_android_24.xml
查看文件 @
95c266d
sample-app-com
pose
/src/main/res/drawable/outline_mic_24.xml → sample-app-com
mon
/src/main/res/drawable/outline_mic_24.xml
查看文件 @
95c266d
sample-app-com
pose
/src/main/res/drawable/outline_mic_off_24.xml → sample-app-com
mon
/src/main/res/drawable/outline_mic_off_24.xml
查看文件 @
95c266d
sample-app-com
pose
/src/main/res/drawable/outline_videocam_24.xml → sample-app-com
mon
/src/main/res/drawable/outline_videocam_24.xml
查看文件 @
95c266d
sample-app-com
pose
/src/main/res/drawable/outline_videocam_off_24.xml → sample-app-com
mon
/src/main/res/drawable/outline_videocam_off_24.xml
查看文件 @
95c266d
sample-app/src/main/java/io/livekit/android/sample/CallActivity.kt
查看文件 @
95c266d
package io.livekit.android.sample
import android.app.Activity
import android.media.AudioManager
import android.media.projection.MediaProjectionManager
import android.os.Bundle
import android.os.Parcelable
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.ajalt.timberkt.Timber
import com.google.android.material.tabs.TabLayoutMediator
import com.snakydesign.livedataextensions.combineLatest
import com.xwray.groupie.GroupieAdapter
import io.livekit.android.room.track.LocalVideoTrack
...
...
@@ -20,12 +23,23 @@ class CallActivity : AppCompatActivity() {
CallViewModel(args.url, args.token, application)
}
lateinit var binding: CallActivityBinding
var tabLayoutMediator: TabLayoutMediator? = null
val focusChangeListener = AudioManager.OnAudioFocusChangeListener {}
private var previousSpeakerphoneOn = true
private var previousMicrophoneMute = false
private val screenCaptureIntentLauncher =
registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
val resultCode = result.resultCode
val data = result.data
if (resultCode != Activity.RESULT_OK || data == null) {
return@registerForActivityResult
}
viewModel.setScreenshare(true, data)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
...
@@ -33,44 +47,71 @@ class CallActivity : AppCompatActivity() {
setContentView(binding.root)
// Viewpager setup
// Audience row setup
binding.audienceRow.layoutManager =
LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
val adapter = GroupieAdapter()
binding.
viewPager
.apply {
binding.
audienceRow
.apply {
this.adapter = adapter
}
combineLatest(
viewModel.room,
viewModel.
remoteP
articipants
viewModel.
p
articipants
) { room, participants -> room to participants }
.observe(this) {
tabLayoutMediator?.detach()
tabLayoutMediator = null
val (room, participants) = it
val items = participants.map { participant -> ParticipantItem(room, participant) }
adapter.update(items)
tabLayoutMediator =
TabLayoutMediator(binding.tabs, binding.viewPager) { tab, position ->
tab.text = participants[position].identity
}
tabLayoutMediator?.attach()
}
// speaker view setup
viewModel.room.observe(this) { room ->
room.initVideoRenderer(binding.
pipVideo
View)
room.initVideoRenderer(binding.
speaker
View)
val videoTrack = room.localParticipant.videoTracks.values
.firstOrNull()
?.track as? LocalVideoTrack
videoTrack?.let {
it.addRenderer(binding.
pipVideo
View)
it.addRenderer(binding.
speaker
View)
}
}
// Controls setup
viewModel.videoEnabled.observe(this) { enabled ->
binding.camera.setOnClickListener { viewModel.setCameraEnabled(!enabled) }
binding.camera.setImageResource(
if (enabled) R.drawable.outline_videocam_24
else R.drawable.outline_videocam_off_24
)
binding.flipCamera.isEnabled = enabled
}
viewModel.micEnabled.observe(this) { enabled ->
binding.mic.setOnClickListener { viewModel.setMicEnabled(!enabled) }
binding.mic.setImageResource(
if (enabled) R.drawable.outline_mic_24
else R.drawable.outline_mic_off_24
)
}
binding.flipCamera.setOnClickListener { viewModel.flipCamera() }
viewModel.screenshareEnabled.observe(this) { enabled ->
binding.screenShare.setOnClickListener {
if (enabled) {
viewModel.setScreenshare(!enabled)
} else {
requestMediaProjection()
}
}
binding.screenShare.setImageResource(
if (enabled) R.drawable.baseline_cast_connected_24
else R.drawable.baseline_cast_24
)
}
// Grab audio focus for video call
val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
with(audioManager) {
previousSpeakerphoneOn = isSpeakerphoneOn
...
...
@@ -91,10 +132,19 @@ class CallActivity : AppCompatActivity() {
}
}
private fun requestMediaProjection() {
val mediaProjectionManager =
getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
screenCaptureIntentLauncher.launch(mediaProjectionManager.createScreenCaptureIntent())
}
override fun onDestroy() {
super.onDestroy()
binding.pipVideoView.release()
// Release video views
binding.speakerView.release()
// Undo audio mode changes
val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
with(audioManager) {
isSpeakerphoneOn = previousSpeakerphoneOn
...
...
sample-app/src/main/java/io/livekit/android/sample/CallViewModel.kt
查看文件 @
95c266d
package io.livekit.android.sample
import android.app.Application
import android.content.Intent
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.
github.ajalt.timberkt.Timber
import com.
snakydesign.livedataextensions.distinctUntilChanged
import io.livekit.android.ConnectOptions
import io.livekit.android.LiveKit
import io.livekit.android.events.RoomEvent
import io.livekit.android.events.collect
import io.livekit.android.room.Room
import io.livekit.android.room.RoomListener
import io.livekit.android.room.participant.Participant
import io.livekit.android.room.participant.RemoteParticipant
import io.livekit.android.room.track.CameraPosition
import io.livekit.android.room.track.LocalVideoTrack
import io.livekit.android.room.track.Track
import io.livekit.android.sample.util.hide
import kotlinx.coroutines.launch
class CallViewModel(
val url: String,
val token: String,
application: Application
) : AndroidViewModel(application)
, RoomListener
{
) : AndroidViewModel(application) {
private val mutableRoom = MutableLiveData<Room>()
val room: LiveData<Room> = mutableRoom
private val mutableRemoteParticipants = MutableLiveData<List<RemoteParticipant>>()
val remoteParticipants: LiveData<List<RemoteParticipant>> = mutableRemoteParticipants
val room = mutableRoom.hide()
private val mutableParticipants = MutableLiveData<List<Participant>>()
val participants = mutableParticipants.hide()
private val mutableActiveSpeaker = MutableLiveData<Participant>()
val activeSpeaker = mutableActiveSpeaker.hide().distinctUntilChanged()
private val mutableVideoEnabled = MutableLiveData<Boolean>()
val videoEnabled = mutableVideoEnabled.hide().distinctUntilChanged()
private val mutableMicEnabled = MutableLiveData<Boolean>()
val micEnabled = mutableMicEnabled.hide().distinctUntilChanged()
private val mutableScreenshareEnabled = MutableLiveData<Boolean>()
val screenshareEnabled = mutableScreenshareEnabled.hide().distinctUntilChanged()
init {
viewModelScope.launch {
...
...
@@ -31,9 +44,15 @@ class CallViewModel(
url,
token,
ConnectOptions(),
this@CallViewMode
l
nul
l
)
launch {
room.events.collect {
handleRoomEvent(it)
}
}
val localParticipant = room.localParticipant
val audioTrack = localParticipant.createAudioTrack()
localParticipant.publishAudioTrack(audioTrack)
...
...
@@ -42,49 +61,95 @@ class CallViewModel(
videoTrack.startCapture()
updateParticipants(room)
mutableActiveSpeaker.value = localParticipant
mutableRoom.value = room
mutableVideoEnabled.value =
!(localParticipant.getTrackPublication(Track.Source.CAMERA)?.muted ?: false)
mutableMicEnabled.value =
!(localParticipant.getTrackPublication(Track.Source.MICROPHONE)?.muted ?: false)
mutableScreenshareEnabled.value = false
}
}
private fun handleRoomEvent(event: RoomEvent) {
when (event) {
is RoomEvent.ParticipantConnected -> updateParticipants(event.room)
is RoomEvent.ParticipantDisconnected -> updateParticipants(event.room)
is RoomEvent.ActiveSpeakersChanged -> handleActiveSpeakersChanged(event.speakers)
}
}
private fun updateParticipants(room: Room) {
mutableRemoteParticipants.postValue(
room.remoteParticipants
.keys
.sortedBy { it }
.mapNotNull { room.remoteParticipants[it] }
mutableParticipants.postValue(
listOf(room.localParticipant) +
room.remoteParticipants
.keys
.sortedBy { it }
.mapNotNull { room.remoteParticipants[it] }
)
}
fun handleActiveSpeakersChanged(speakers: List<Participant>) {
// If old active speaker is still active, don't change.
if (speakers.isEmpty() || speakers.contains(mutableActiveSpeaker.value)) {
return
}
val newSpeaker = speakers.firstOrNull() ?: return
mutableActiveSpeaker.postValue(newSpeaker)
}
override fun onCleared() {
super.onCleared()
mutableRoom.value?.disconnect()
}
override fun onDisconnect(room: Room, error: Exception?) {
fun setCameraEnabled(enabled: Boolean) {
val localParticipant = room.value?.localParticipant ?: return
viewModelScope.launch {
localParticipant.setCameraEnabled(enabled)
mutableVideoEnabled.postValue(enabled)
}
}
override fun onParticipantConnected(
room: Room,
participant: RemoteParticipant
) {
updateParticipants(room)
fun setMicEnabled(enabled: Boolean) {
val localParticipant = room.value?.localParticipant ?: return
viewModelScope.launch {
localParticipant.setMicrophoneEnabled(enabled)
mutableMicEnabled.postValue(enabled)
}
}
override fun onParticipantDisconnected(
room: Room,
participant: RemoteParticipant
fun setScreenshare(
enabled: Boolean,
mediaProjectionPermissionResultData: Intent? = null
) {
updateParticipants(room)
}
val localParticipant = room.value?.localParticipant ?: return
override fun onFailedToConnect(room: Room, error: Exception) {
viewModelScope.launch {
localParticipant.setScreenShareEnabled(enabled, mediaProjectionPermissionResultData)
mutableScreenshareEnabled.postValue(enabled)
}
}
override fun onActiveSpeakersChanged(speakers: List<Participant>, room: Room) {
Timber.i { "active speakers changed ${speakers.count()}" }
}
fun flipCamera() {
val localParticipant = room.value?.localParticipant ?: return
val localVideoTrack = localParticipant
.getTrackPublication(Track.Source.CAMERA)
?.track as? LocalVideoTrack
?: return
override fun onMetadataChanged(participant: Participant, prevMetadata: String?, room: Room) {
Timber.i { "Participant metadata changed: ${participant.identity}" }
val currentOptions = localVideoTrack.options
val newPosition = when (currentOptions.position) {
CameraPosition.FRONT -> CameraPosition.BACK
CameraPosition.BACK -> CameraPosition.FRONT
null -> null
}
if (newPosition != null) {
localVideoTrack.restartTrack(options = currentOptions.copy(position = newPosition))
}
}
}
...
...
sample-app/src/main/java/io/livekit/android/sample/ParticipantItem.kt
查看文件 @
95c266d
...
...
@@ -5,6 +5,7 @@ import com.github.ajalt.timberkt.Timber
import com.xwray.groupie.viewbinding.BindableItem
import com.xwray.groupie.viewbinding.GroupieViewHolder
import io.livekit.android.room.Room
import io.livekit.android.room.participant.Participant
import io.livekit.android.room.participant.ParticipantListener
import io.livekit.android.room.participant.RemoteParticipant
import io.livekit.android.room.track.*
...
...
@@ -12,7 +13,7 @@ import io.livekit.android.sample.databinding.ParticipantItemBinding
class ParticipantItem(
val room: Room,
val
remoteParticipant: Remote
Participant
val
participant:
Participant
) :
BindableItem<ParticipantItemBinding>() {
...
...
@@ -27,13 +28,14 @@ class ParticipantItem(
override fun bind(viewBinding: ParticipantItemBinding, position: Int) {
viewBinding.run {
remoteP
articipant.listener = object : ParticipantListener {
p
articipant.listener = object : ParticipantListener {
override fun onTrackSubscribed(
track: Track,
publication: RemoteTrackPublication,
participant: RemoteParticipant
) {
if (track is VideoTrack) {
if (track !is VideoTrack) return
if (publication.source == Track.Source.CAMERA) {
setupVideoIfNeeded(track, viewBinding)
}
}
...
...
@@ -54,9 +56,7 @@ class ParticipantItem(
}
private fun getVideoTrack(): VideoTrack? {
return remoteParticipant
.videoTracks.values
.firstOrNull()?.track as? VideoTrack
return participant.getTrackPublication(Track.Source.CAMERA)?.track as? VideoTrack
}
internal fun setupVideoIfNeeded(videoTrack: VideoTrack, viewBinding: ParticipantItemBinding) {
...
...
sample-app/src/main/res/drawable/ic_round_mic_24.xml
已删除
100644 → 0
查看文件 @
36384a6
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportWidth=
"24"
android:viewportHeight=
"24"
android:tint=
"?attr/colorControlNormal"
>
<path
android:fillColor=
"@android:color/white"
android:pathData=
"M12,14c1.66,0 3,-1.34 3,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.91,11c-0.49,0 -0.9,0.36 -0.98,0.85C16.52,14.2 14.47,16 12,16s-4.52,-1.8 -4.93,-4.15c-0.08,-0.49 -0.49,-0.85 -0.98,-0.85 -0.61,0 -1.09,0.54 -1,1.14 0.49,3 2.89,5.35 5.91,5.78L11,20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.08c3.02,-0.43 5.42,-2.78 5.91,-5.78 0.1,-0.6 -0.39,-1.14 -1,-1.14z"
/>
</vector>
sample-app/src/main/res/drawable/ic_round_mic_off_24.xml
已删除
100644 → 0
查看文件 @
36384a6
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportWidth=
"24"
android:viewportHeight=
"24"
android:tint=
"?attr/colorControlNormal"
>
<path
android:fillColor=
"@android:color/white"
android:pathData=
"M15,10.6L15,5c0,-1.66 -1.34,-3 -3,-3 -1.54,0 -2.79,1.16 -2.96,2.65L15,10.6zM18.08,11c-0.41,0 -0.77,0.3 -0.83,0.71 -0.05,0.32 -0.12,0.64 -0.22,0.93l1.27,1.27c0.3,-0.6 0.52,-1.25 0.63,-1.94 0.07,-0.51 -0.33,-0.97 -0.85,-0.97zM3.71,3.56c-0.39,0.39 -0.39,1.02 0,1.41L9,10.27v0.43c0,1.19 0.6,2.32 1.63,2.91 0.75,0.43 1.41,0.44 2.02,0.31l1.66,1.66c-0.71,0.33 -1.5,0.52 -2.31,0.52 -2.54,0 -4.88,-1.77 -5.25,-4.39 -0.06,-0.41 -0.42,-0.71 -0.83,-0.71 -0.52,0 -0.92,0.46 -0.85,0.97 0.46,2.96 2.96,5.3 5.93,5.75L11,20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.28c0.91,-0.13 1.77,-0.45 2.55,-0.9l3.49,3.49c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L5.12,3.56c-0.39,-0.39 -1.02,-0.39 -1.41,0z"
/>
</vector>
sample-app/src/main/res/drawable/ic_round_videocam_24.xml
已删除
100644 → 0
查看文件 @
36384a6
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportWidth=
"24"
android:viewportHeight=
"24"
android:tint=
"?attr/colorControlNormal"
>
<path
android:fillColor=
"@android:color/white"
android:pathData=
"M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l2.29,2.29c0.63,0.63 1.71,0.18 1.71,-0.71V8.91c0,-0.89 -1.08,-1.34 -1.71,-0.71L17,10.5z"
/>
</vector>
sample-app/src/main/res/drawable/ic_round_videocam_off_24.xml
已删除
100644 → 0
查看文件 @
36384a6
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportWidth=
"24"
android:viewportHeight=
"24"
android:tint=
"?attr/colorControlNormal"
>
<path
android:fillColor=
"@android:color/white"
android:pathData=
"M21,14.2V8.91c0,-0.89 -1.08,-1.34 -1.71,-0.71L17,10.5V7c0,-0.55 -0.45,-1 -1,-1h-5.61l8.91,8.91c0.62,0.63 1.7,0.18 1.7,-0.71zM2.71,2.56c-0.39,0.39 -0.39,1.02 0,1.41L4.73,6H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.21,0 0.39,-0.08 0.55,-0.18l2.48,2.48c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.12,2.56c-0.39,-0.39 -1.02,-0.39 -1.41,0z"
/>
</vector>
sample-app/src/main/res/layout/call_activity.xml
查看文件 @
95c266d
...
...
@@ -4,58 +4,59 @@
android:layout_height=
"match_parent"
android:keepScreenOn=
"true"
>
<com.google.android.material.tabs.TabLayout
android:id=
"@+id/tabs"
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
<io.livekit.android.renderer.TextureViewRenderer
android:id=
"@+id/speaker_view"
android:layout_width=
"0dp"
android:layout_height=
"0dp"
app:layout_constraintBottom_toTopOf=
"@id/audience_row"
app:layout_constraintTop_toTopOf=
"parent"
app:tabMode=
"auto"
/>
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
/>
<androidx.viewpager2.widget.ViewPager2
android:id=
"@+id/view_pager"
<androidx.recyclerview.widget.RecyclerView
android:id=
"@+id/audience_row"
android:layout_width=
"match_parent"
android:layout_height=
"0dp"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@id/tabs"
/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=
"200dp"
android:layout_height=
"200dp"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
>
<io.livekit.android.renderer.TextureViewRenderer
android:id=
"@+id/pip_video_view"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_margin=
"16dp"
/>
<LinearLayout
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_margin=
"30dp"
android:orientation=
"horizontal"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
>
android:layout_height=
"120dp"
app:layout_constraintBottom_toTopOf=
"@id/controls_box"
/>
<ImageButton
android:id=
"@+id/mic_button"
android:layout_width=
"48dp"
android:layout_height=
"48dp"
android:src=
"@drawable/ic_round_mic_24"
/>
<Space
android:layout_width=
"20dp"
android:layout_height=
"1dp"
/>
<ImageButton
android:id=
"@+id/video_button"
android:layout_width=
"48dp"
android:layout_height=
"48dp"
android:src=
"@drawable/ic_round_videocam_24"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id=
"@+id/controls_box"
android:layout_width=
"match_parent"
android:layout_height=
"60dp"
android:gravity=
"center"
android:orientation=
"horizontal"
app:layout_constraintBottom_toBottomOf=
"parent"
>
<ImageView
android:id=
"@+id/camera"
android:layout_width=
"@dimen/control_size"
android:layout_height=
"@dimen/control_size"
android:background=
"?android:attr/selectableItemBackground"
android:padding=
"@dimen/control_padding"
android:src=
"@drawable/outline_videocam_24"
/>
<ImageView
android:id=
"@+id/mic"
android:layout_width=
"@dimen/control_size"
android:layout_height=
"@dimen/control_size"
android:background=
"?android:attr/selectableItemBackground"
android:padding=
"@dimen/control_padding"
android:src=
"@drawable/outline_mic_24"
/>
<ImageView
android:id=
"@+id/flip_camera"
android:layout_width=
"@dimen/control_size"
android:layout_height=
"@dimen/control_size"
android:background=
"?android:attr/selectableItemBackground"
android:padding=
"@dimen/control_padding"
android:src=
"@drawable/outline_flip_camera_android_24"
/>
<ImageView
android:id=
"@+id/screen_share"
android:layout_width=
"@dimen/control_size"
android:layout_height=
"@dimen/control_size"
android:background=
"?android:attr/selectableItemBackground"
android:padding=
"@dimen/control_padding"
android:src=
"@drawable/baseline_cast_24"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
...
...
sample-app/src/main/res/layout/participant_item.xml
查看文件 @
95c266d
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:layout_width=
"wrap_content"
android:layout_height=
"match_parent"
>
<io.livekit.android.renderer.TextureViewRenderer
android:id=
"@+id/renderer"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
/>
</FrameLayout>
\ No newline at end of file
android:layout_width=
"0dp"
android:layout_height=
"match_parent"
app:layout_constraintDimensionRatio=
"1:1"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...
...
sample-app/src/main/res/values/dimens.xml
0 → 100644
查看文件 @
95c266d
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen
name=
"control_size"
>
40dp
</dimen>
<dimen
name=
"control_padding"
>
4dp
</dimen>
</resources>
\ No newline at end of file
...
...
sample-app/src/main/res/values/styles.xml
查看文件 @
95c266d
...
...
@@ -6,7 +6,7 @@
<item
name=
"colorPrimary"
>
@color/colorPrimary
</item>
<item
name=
"colorPrimaryDark"
>
@color/colorPrimaryDark
</item>
<item
name=
"colorAccent"
>
@color/colorAccent
</item>
<item
name=
"android:windowBackground"
>
#000000
</item>
<item
name=
"android:windowBackground"
>
@android:color/black
</item>
</style>
</resources>
...
...
请
注册
或
登录
后发表评论