11/*
2- * Copyright 2023-2024 LiveKit, Inc.
2+ * Copyright 2023-2026 LiveKit, Inc.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -19,13 +19,16 @@ package io.livekit.android.room
1919import io.livekit.android.events.ParticipantEvent
2020import io.livekit.android.events.RoomEvent
2121import io.livekit.android.room.participant.AudioTrackPublishOptions
22+ import io.livekit.android.room.participant.RemoteParticipant
2223import io.livekit.android.room.track.Track
24+ import io.livekit.android.room.track.TrackException
2325import io.livekit.android.test.MockE2ETest
2426import io.livekit.android.test.assert.assertIsClass
2527import io.livekit.android.test.events.EventCollector
2628import io.livekit.android.test.mock.TestData
2729import io.livekit.android.test.mock.room.track.createMockLocalAudioTrack
2830import kotlinx.coroutines.ExperimentalCoroutinesApi
31+ import livekit.LivekitModels
2932import livekit.LivekitRtc
3033import livekit.LivekitRtc.ParticipantUpdate
3134import livekit.LivekitRtc.SignalResponse
@@ -115,4 +118,54 @@ class RoomParticipantEventMockE2ETest : MockE2ETest() {
115118 assertIsClass(ParticipantEvent .LocalTrackSubscribed ::class .java, participantEvents[0 ])
116119 }
117120 }
121+
122+ @Test
123+ fun trackSubscriptionFailed () = runTest {
124+ connect()
125+
126+ wsFactory.receiveMessage(TestData .PARTICIPANT_JOIN )
127+
128+ val remoteParticipant = room.getParticipantBySid(TestData .REMOTE_PARTICIPANT .sid) as RemoteParticipant
129+ val roomCollector = EventCollector (room.events, coroutineRule.scope)
130+ val participantCollector = EventCollector (remoteParticipant.events, coroutineRule.scope)
131+
132+ wsFactory.receiveMessage(
133+ with (SignalResponse .newBuilder()) {
134+ subscriptionResponse = with (LivekitRtc .SubscriptionResponse .newBuilder()) {
135+ trackSid = TestData .REMOTE_AUDIO_TRACK .sid
136+ err = LivekitModels .SubscriptionError .SE_CODEC_UNSUPPORTED
137+ build()
138+ }
139+ build()
140+ },
141+ )
142+
143+ val roomEvents = roomCollector.stopCollecting()
144+ val participantEvents = participantCollector.stopCollecting()
145+
146+ // Verify room events
147+ run {
148+ assertEquals(1 , roomEvents.size)
149+ assertIsClass(RoomEvent .TrackSubscriptionFailed ::class .java, roomEvents[0 ])
150+
151+ val event = roomEvents.first() as RoomEvent .TrackSubscriptionFailed
152+ assertEquals(room, event.room)
153+ assertEquals(TestData .REMOTE_AUDIO_TRACK .sid, event.sid)
154+ assertEquals(remoteParticipant, event.participant)
155+ assertIsClass(TrackException .MediaException ::class .java, event.exception)
156+ assertEquals(" Codec not supported" , event.exception.message)
157+ }
158+
159+ // Verify participant events
160+ run {
161+ assertEquals(1 , participantEvents.size)
162+ assertIsClass(ParticipantEvent .TrackSubscriptionFailed ::class .java, participantEvents[0 ])
163+
164+ val event = participantEvents.first() as ParticipantEvent .TrackSubscriptionFailed
165+ assertEquals(remoteParticipant, event.participant)
166+ assertEquals(TestData .REMOTE_AUDIO_TRACK .sid, event.sid)
167+ assertIsClass(TrackException .MediaException ::class .java, event.exception)
168+ assertEquals(" Codec not supported" , event.exception.message)
169+ }
170+ }
118171}
0 commit comments