davidliu
Committed by GitHub

Add Room.isRecording to surface if the room is being recorded (#200)

* Add Room.isRecording to surface if the room is being recorded

* Add livekit-lint/bin to git ignore
@@ -15,3 +15,4 @@ @@ -15,3 +15,4 @@
15 /captures 15 /captures
16 .externalNativeBuild 16 .externalNativeBuild
17 .cxx 17 .cxx
  18 +/livekit-lint/bin
@@ -169,6 +169,11 @@ sealed class RoomEvent(val room: Room) : Event() { @@ -169,6 +169,11 @@ sealed class RoomEvent(val room: Room) : Event() {
169 val newPermissions: ParticipantPermission?, 169 val newPermissions: ParticipantPermission?,
170 val oldPermissions: ParticipantPermission?, 170 val oldPermissions: ParticipantPermission?,
171 ) : RoomEvent(room) 171 ) : RoomEvent(room)
  172 +
  173 + /**
  174 + * The recording of a room has started/stopped.
  175 + */
  176 + class RecordingStatusChanged(room: Room, isRecording: Boolean) : RoomEvent(room)
172 } 177 }
173 178
174 enum class DisconnectReason { 179 enum class DisconnectReason {
@@ -108,6 +108,11 @@ constructor( @@ -108,6 +108,11 @@ constructor(
108 var metadata: String? by flowDelegate(null) 108 var metadata: String? by flowDelegate(null)
109 private set 109 private set
110 110
  111 + @FlowObservable
  112 + @get:FlowObservable
  113 + var isRecording: Boolean by flowDelegate(false)
  114 + private set
  115 +
111 /** 116 /**
112 * Automatically manage quality of subscribed video tracks, subscribe to the 117 * Automatically manage quality of subscribed video tracks, subscribe to the
113 * an appropriate resolution based on the size of the video elements that tracks 118 * an appropriate resolution based on the size of the video elements that tracks
@@ -271,6 +276,11 @@ constructor( @@ -271,6 +276,11 @@ constructor(
271 name = response.room.name 276 name = response.room.name
272 metadata = response.room.metadata 277 metadata = response.room.metadata
273 278
  279 + if (response.room.activeRecording != isRecording) {
  280 + isRecording = response.room.activeRecording
  281 + eventBus.postEvent(RoomEvent.RecordingStatusChanged(this, isRecording), coroutineScope)
  282 + }
  283 +
274 if (!response.hasParticipant()) { 284 if (!response.hasParticipant()) {
275 listener?.onFailedToConnect(this, RoomException.ConnectException("server didn't return any participants")) 285 listener?.onFailedToConnect(this, RoomException.ConnectException("server didn't return any participants"))
276 return 286 return
@@ -462,6 +472,7 @@ constructor( @@ -462,6 +472,7 @@ constructor(
462 sid = null 472 sid = null
463 metadata = null 473 metadata = null
464 name = null 474 name = null
  475 + isRecording = false
465 } 476 }
466 477
467 private fun handleDisconnect(reason: DisconnectReason) { 478 private fun handleDisconnect(reason: DisconnectReason) {
@@ -673,7 +684,16 @@ constructor( @@ -673,7 +684,16 @@ constructor(
673 val oldMetadata = metadata 684 val oldMetadata = metadata
674 metadata = update.metadata 685 metadata = update.metadata
675 686
676 - eventBus.postEvent(RoomEvent.RoomMetadataChanged(this, metadata, oldMetadata), coroutineScope) 687 + val oldIsRecording = isRecording
  688 + isRecording = update.activeRecording
  689 +
  690 + if (oldMetadata != metadata) {
  691 + eventBus.postEvent(RoomEvent.RoomMetadataChanged(this, metadata, oldMetadata), coroutineScope)
  692 + }
  693 +
  694 + if (oldIsRecording != isRecording) {
  695 + eventBus.postEvent(RoomEvent.RecordingStatusChanged(this, isRecording), coroutineScope)
  696 + }
677 } 697 }
678 698
679 /** 699 /**
@@ -5,6 +5,7 @@ import android.net.ConnectivityManager @@ -5,6 +5,7 @@ import android.net.ConnectivityManager
5 import android.net.Network 5 import android.net.Network
6 import androidx.test.platform.app.InstrumentationRegistry 6 import androidx.test.platform.app.InstrumentationRegistry
7 import io.livekit.android.MockE2ETest 7 import io.livekit.android.MockE2ETest
  8 +import io.livekit.android.assert.assertIsClassList
8 import io.livekit.android.events.* 9 import io.livekit.android.events.*
9 import io.livekit.android.mock.MockAudioStreamTrack 10 import io.livekit.android.mock.MockAudioStreamTrack
10 import io.livekit.android.mock.MockMediaStream 11 import io.livekit.android.mock.MockMediaStream
@@ -92,15 +93,25 @@ class RoomMockE2ETest : MockE2ETest() { @@ -92,15 +93,25 @@ class RoomMockE2ETest : MockE2ETest() {
92 fun roomUpdateTest() = runTest { 93 fun roomUpdateTest() = runTest {
93 connect() 94 connect()
94 val eventCollector = EventCollector(room.events, coroutineRule.scope) 95 val eventCollector = EventCollector(room.events, coroutineRule.scope)
  96 + val roomUpdate = SignalClientTest.ROOM_UPDATE
95 wsFactory.listener.onMessage(wsFactory.ws, SignalClientTest.ROOM_UPDATE.toOkioByteString()) 97 wsFactory.listener.onMessage(wsFactory.ws, SignalClientTest.ROOM_UPDATE.toOkioByteString())
96 val events = eventCollector.stopCollecting() 98 val events = eventCollector.stopCollecting()
97 99
98 - Assert.assertEquals(  
99 - SignalClientTest.ROOM_UPDATE.roomUpdate.room.metadata, 100 + assertEquals(
  101 + roomUpdate.roomUpdate.room.metadata,
100 room.metadata 102 room.metadata
101 ) 103 )
102 - Assert.assertEquals(1, events.size)  
103 - Assert.assertEquals(true, events[0] is RoomEvent.RoomMetadataChanged) 104 + assertEquals(
  105 + roomUpdate.roomUpdate.room.activeRecording,
  106 + room.isRecording
  107 + )
  108 + assertIsClassList(
  109 + listOf(
  110 + RoomEvent.RoomMetadataChanged::class.java,
  111 + RoomEvent.RecordingStatusChanged::class.java,
  112 + ),
  113 + events
  114 + )
104 } 115 }
105 116
106 @Test 117 @Test
@@ -5,6 +5,7 @@ import android.net.ConnectivityManager @@ -5,6 +5,7 @@ import android.net.ConnectivityManager
5 import android.net.Network 5 import android.net.Network
6 import androidx.test.core.app.ApplicationProvider 6 import androidx.test.core.app.ApplicationProvider
7 import androidx.test.platform.app.InstrumentationRegistry 7 import androidx.test.platform.app.InstrumentationRegistry
  8 +import io.livekit.android.assert.assertIsClassList
8 import io.livekit.android.audio.NoAudioHandler 9 import io.livekit.android.audio.NoAudioHandler
9 import io.livekit.android.coroutines.TestCoroutineRule 10 import io.livekit.android.coroutines.TestCoroutineRule
10 import io.livekit.android.events.* 11 import io.livekit.android.events.*
@@ -104,6 +105,28 @@ class RoomTest { @@ -104,6 +105,28 @@ class RoomTest {
104 assertEquals(roomInfo.name, room.name) 105 assertEquals(roomInfo.name, room.name)
105 assertEquals(Room.Sid(roomInfo.sid), room.sid) 106 assertEquals(Room.Sid(roomInfo.sid), room.sid)
106 assertEquals(roomInfo.metadata, room.metadata) 107 assertEquals(roomInfo.metadata, room.metadata)
  108 + assertEquals(roomInfo.activeRecording, room.isRecording)
  109 + }
  110 +
  111 + @Test
  112 + fun roomUpdate() = runTest {
  113 + connect()
  114 + val update = SignalClientTest.ROOM_UPDATE.roomUpdate.room
  115 +
  116 + val eventCollector = EventCollector(room.events, coroutineRule.scope)
  117 + room.onRoomUpdate(update)
  118 + val events = eventCollector.stopCollecting()
  119 +
  120 + assertEquals(update.metadata, room.metadata)
  121 + assertEquals(update.activeRecording, room.isRecording)
  122 +
  123 + assertIsClassList(
  124 + listOf(
  125 + RoomEvent.RoomMetadataChanged::class.java,
  126 + RoomEvent.RecordingStatusChanged::class.java,
  127 + ),
  128 + events
  129 + )
107 } 130 }
108 131
109 @Test 132 @Test
@@ -144,6 +167,7 @@ class RoomTest { @@ -144,6 +167,7 @@ class RoomTest {
144 assertNull(room.sid) 167 assertNull(room.sid)
145 assertNull(room.metadata) 168 assertNull(room.metadata)
146 assertNull(room.name) 169 assertNull(room.name)
  170 + assertFalse(room.isRecording)
147 } 171 }
148 172
149 @Test 173 @Test
@@ -163,7 +187,7 @@ class RoomTest { @@ -163,7 +187,7 @@ class RoomTest {
163 assertNull(room.sid) 187 assertNull(room.sid)
164 assertNull(room.metadata) 188 assertNull(room.metadata)
165 assertNull(room.name) 189 assertNull(room.name)
166 - 190 + assertFalse(room.isRecording)
167 } 191 }
168 192
169 @Test 193 @Test
@@ -310,6 +310,7 @@ class SignalClientTest : BaseTest() { @@ -310,6 +310,7 @@ class SignalClientTest : BaseTest() {
310 roomUpdate = with(LivekitRtc.RoomUpdate.newBuilder()) { 310 roomUpdate = with(LivekitRtc.RoomUpdate.newBuilder()) {
311 room = with(LivekitModels.Room.newBuilder()) { 311 room = with(LivekitModels.Room.newBuilder()) {
312 metadata = "metadata" 312 metadata = "metadata"
  313 + activeRecording = true
313 build() 314 build()
314 } 315 }
315 build() 316 build()