@@ -887,42 +887,47 @@ void WebRTCProviderManager::OnConnectionStateChanged(bool connected, const uint1
887887 }
888888 else
889889 {
890- WebrtcTransport * transport = GetTransport (sessionId);
891- if (transport == nullptr )
892- {
890+ // Schedule cleanup on Matter thread to ensure proper locking when calling RemoveSession.
891+ // Safe to capture 'this' by value: WebRTCProviderManager is a member of the global CameraDevice
892+ // object which has static storage duration and lives for the entire program lifetime.
893+ DeviceLayer::SystemLayer ().ScheduleLambda ([this , sessionId]() {
894+ WebrtcTransport * transport = GetTransport (sessionId);
895+ if (transport == nullptr )
896+ {
897+ ChipLogProgress (Camera,
898+ " Transport not found for session %u during disconnect; session may have already been cleaned up" ,
899+ sessionId);
900+ return ;
901+ }
893902
894- ChipLogProgress (Camera,
895- " Transport not found for session %u during disconnect; session may have already been cleaned up" ,
896- sessionId);
897- return ;
898- }
903+ // Connection was closed/disconnected by the peer - clean up the session
904+ ChipLogProgress (Camera, " Peer connection closed for session %u, cleaning up resources" , sessionId);
899905
900- // Connection was closed/disconnected by the peer - clean up the session
901- ChipLogProgress (Camera, " Peer connection closed for session %u, cleaning up resources" , sessionId);
906+ // Release the Video and Audio Streams from the CameraAVStreamManagement
907+ // cluster and update the reference counts.
908+ ReleaseAudioVideoStreams (sessionId);
902909
903- // Release the Video and Audio Streams from the CameraAVStreamManagement
904- // cluster and update the reference counts.
905- ReleaseAudioVideoStreams (sessionId);
906-
907- // Capture args before unregistering in case the transport is invalidated
908- WebrtcTransport::RequestArgs args = transport->GetRequestArgs ();
910+ // Capture args before unregistering in case the transport is invalidated
911+ WebrtcTransport::RequestArgs args = transport->GetRequestArgs ();
909912
910- // Unregister the transport from the media controller
911- UnregisterWebrtcTransport (sessionId);
913+ // Unregister the transport from the media controller
914+ UnregisterWebrtcTransport (sessionId);
912915
913- // Remove from session maps
914- mSessionIdMap .erase (ScopedNodeId (args.peerNodeId , args.fabricIndex ));
916+ // Remove from session maps
917+ mSessionIdMap .erase (ScopedNodeId (args.peerNodeId , args.fabricIndex ));
915918
916- // Remove from current sessions list in the WebRTC Transport Provider
917- if (mWebRTCTransportProvider != nullptr )
918- {
919- mWebRTCTransportProvider ->RemoveSession (sessionId);
920- }
919+ // Remove from current sessions list in the WebRTC Transport Provider
920+ // This MUST be called on the Matter thread with the stack lock held
921+ if (mWebRTCTransportProvider != nullptr )
922+ {
923+ mWebRTCTransportProvider ->RemoveSession (sessionId);
924+ }
921925
922- // Finally, remove and destroy the transport
923- mWebrtcTransportMap .erase (sessionId);
926+ // Finally, remove and destroy the transport
927+ mWebrtcTransportMap .erase (sessionId);
924928
925- ChipLogProgress (Camera, " Session %u cleanup completed" , sessionId);
929+ ChipLogProgress (Camera, " Session %u cleanup completed" , sessionId);
930+ });
926931 }
927932}
928933
@@ -975,7 +980,9 @@ CHIP_ERROR WebRTCProviderManager::SendICECandidatesCommand(Messaging::ExchangeMa
975980 ChipLogError (Camera, " WebTransport not found for the sessionId: %u" , sessionId);
976981 return CHIP_ERROR_INTERNAL;
977982 }
978- std::vector<std::string> localCandidates = transport->GetCandidates ();
983+
984+ const std::vector<ICECandidateInfo> & localCandidates = transport->GetCandidates ();
985+
979986 // Build the command
980987 WebRTCTransportRequestor::Commands::ICECandidates::Type command;
981988
@@ -986,9 +993,31 @@ CHIP_ERROR WebRTCProviderManager::SendICECandidatesCommand(Messaging::ExchangeMa
986993 }
987994
988995 std::vector<ICECandidateStruct> iceCandidateStructList;
989- for (const auto & candidate : localCandidates)
996+ for (const auto & candidateInfo : localCandidates)
990997 {
991- ICECandidateStruct iceCandidate = { CharSpan::fromCharString (candidate.c_str ()) };
998+ ICECandidateStruct iceCandidate;
999+ iceCandidate.candidate = CharSpan (candidateInfo.candidate .data (), candidateInfo.candidate .size ());
1000+
1001+ // Set SDPMid if available
1002+ if (!candidateInfo.mid .empty ())
1003+ {
1004+ iceCandidate.SDPMid .SetNonNull (CharSpan (candidateInfo.mid .data (), candidateInfo.mid .size ()));
1005+ }
1006+ else
1007+ {
1008+ iceCandidate.SDPMid .SetNull ();
1009+ }
1010+
1011+ // Set SDPMLineIndex if valid
1012+ if (candidateInfo.mlineIndex >= 0 )
1013+ {
1014+ iceCandidate.SDPMLineIndex .SetNonNull (static_cast <uint16_t >(candidateInfo.mlineIndex ));
1015+ }
1016+ else
1017+ {
1018+ iceCandidate.SDPMLineIndex .SetNull ();
1019+ }
1020+
9921021 iceCandidateStructList.push_back (iceCandidate);
9931022 }
9941023
0 commit comments