Bug: "could not find participant" when a participant quickly reconnects
I have an instance of the Go Server SDK that monitors a room. Also, I have iOS client apps that connects to a LiveKit media server.
If an iOS client force disconnects from LiveKit server (like by force killing client app process) and reconnects after a few seconds before LiveKit media server emits a "participant disconnected" message due to timeout then Go LiveKit Server SDK fails with error like: "msg"="could not find participant" "error"=null "participantID"="PA_2rjapiiKp9hi" on media track publication by this iOS client.
The error message comes from room.go: handleMediaTrack function.
Probably, it's because of no "participant connected" event is fired when the client reconnects for the second time before the timeout ends.
which version of the SDK are you using? Can you share specific steps to reproduce the issue?
@davidzhao I'm using v2.1.1
Here's code example for Go Server:
package main
import (
"context"
"fmt"
"github.com/livekit/protocol/livekit"
lksdk "github.com/livekit/server-sdk-go/v2"
"log"
"os"
"os/signal"
"syscall"
)
var roomClient *lksdk.RoomServiceClient
var liveKitServerURL = "http://127.0.0.1:6880"
var apiKey = "devkey"
var apiSecret = "secret"
var roomName = "test"
func main() {
roomClient = lksdk.NewRoomServiceClient(liveKitServerURL, apiKey, apiSecret)
createRoom()
connectToRoom()
// This will block the main function indefinitely
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT)
<-sigChan
}
func createRoom() {
_, err := roomClient.CreateRoom(context.Background(), &livekit.CreateRoomRequest{
Name: roomName,
})
if err != nil {
log.Fatalf("❌ Error creating %v room: %v", roomName, err)
return
}
fmt.Println("Room created: ", roomName)
}
func connectToRoom() {
roomCB := &lksdk.RoomCallback{
OnParticipantConnected: func(participant *lksdk.RemoteParticipant) {
fmt.Println("❇️onParticipantConnected: ", participant.Name(), participant.SID(), participant.Identity())
},
OnParticipantDisconnected: func(participant *lksdk.RemoteParticipant) {
fmt.Println("⭕️Participant disconnected: ", participant.Identity())
},
ParticipantCallback: lksdk.ParticipantCallback{
OnTrackPublished: func(publication *lksdk.RemoteTrackPublication, rp *lksdk.RemoteParticipant) {
fmt.Println("🔔Track published by ", rp.Identity(), rp.SID())
},
OnTrackUnpublished: func(publication *lksdk.RemoteTrackPublication, rp *lksdk.RemoteParticipant) {
fmt.Println("🔕Track unpublished by ", rp.Identity(), rp.SID())
},
},
}
// Connect to a room
_, err := lksdk.ConnectToRoom(liveKitServerURL, lksdk.ConnectInfo{
APIKey: apiKey,
APISecret: apiSecret,
RoomName: roomName,
ParticipantIdentity: "go-server-agent",
}, roomCB)
if err != nil {
log.Fatalf("❌ Error connecting to speaking room: %w", err)
return
}
}
I also can provide code for iOS client. But the steps are:
- Start Go Server.
- Connect to the "test" room from any client (iOS client for my case)
- Publish an audio track and stop publishing (turning on and off mic for iOS device)
- Force close iOS client app
- Relaunch the client
- Publish an audio track again
- Observe
"level"=0 "msg"="could not find participant, deferring track update" "participantID"="PA_PokmPNgaNuvs"message and no "Track published/unpublished" events in Go Server
Here's log I get for the code above:
Room created: test
❇️onParticipantConnected: PA_ZbZP56Y9LXdh DenisIphone
🔔Track published by DenisIphone PA_ZbZP56Y9LXdh
2024/04/25 18:39:50 "level"=0 "msg"="track subscribed" "participant"="DenisIphone" "track"="TR_AMaWYeWpNAXDZK" "kind"="audio"
🔕Track unpublished by DenisIphone PA_ZbZP56Y9LXdh
// < Here I force killed the client app, relaunched it and published audio again >
2024/04/25 18:40:01 "level"=0 "msg"="could not find participant, deferring track update" "participantID"="PA_Hdxd6K5aDkkq"
2024/04/25 18:40:05 "level"=0 "msg"="participant sid update" "sid-old"="PA_ZbZP56Y9LXdh" "sid-new"="PA_Hdxd6K5aDkkq" "identity"="DenisIphone"
2024/04/25 18:40:05 "level"=0 "msg"="running deferred updates for participant" "participantID"="PA_Hdxd6K5aDkkq" "updates"=1
I think it could be related to this PR #447 by @dennwc
As long as it prints running deferred updates for participant, that PR likely works as intended. Without it it will be just participant not found and audio will be lost. Now it at least attempts to re-attach audio.
Probably what's missing is a call to OnTrackPublished when the track reconnects. I need to reproduce it on my side.
@dennwc Hi! Do you have any progress on this?
Thank you for the ping, I didn't check it yet. I'll try testing it this week.
@dennwc Could I help you with something to reproduce the issue?