@@ -173,28 +173,53 @@ private void cleanSurfaceViewRenderer() {
173173 surfaceViewRenderer .clearImage ();
174174 }
175175
176- private VideoTrack getVideoTrackForStreamURL (String streamURL ) {
177- VideoTrack videoTrack = null ;
176+ /**
177+ * Asynchronously retrieves the VideoTrack for the given streamURL.
178+ * This method avoids blocking the UI thread by performing the lookup
179+ * on the WebRTC executor thread and posting the result back to the UI thread.
180+ *
181+ * @param streamURL The stream URL to lookup
182+ * @param callback Callback invoked on UI thread with the VideoTrack (or null if not found)
183+ */
184+ private void getVideoTrackForStreamURL (String streamURL , java .util .function .Consumer <VideoTrack > callback ) {
185+ if (streamURL == null ) {
186+ callback .accept (null );
187+ return ;
188+ }
178189
179- if (streamURL != null ) {
180- ReactContext reactContext = (ReactContext ) getContext ();
181- WebRTCModule module = reactContext .getNativeModule (WebRTCModule .class );
182- MediaStream stream = module .getStreamForReactTag (streamURL );
190+ ReactContext reactContext = (ReactContext ) getContext ();
191+ WebRTCModule module = reactContext .getNativeModule (WebRTCModule .class );
183192
184- if (stream != null ) {
185- List <VideoTrack > videoTracks = stream .videoTracks ;
193+ // Submit lookup to executor thread to avoid blocking UI thread
194+ ThreadUtils .runOnExecutor (() -> {
195+ try {
196+ MediaStream stream = module .getStreamForReactTag (streamURL );
197+ if (stream == null ) {
198+ Log .w (TAG , "Stream not found for URL: " + streamURL );
199+ post (() -> callback .accept (null ));
200+ return ;
201+ }
186202
203+ VideoTrack videoTrack = null ;
204+ List <VideoTrack > videoTracks = stream .videoTracks ;
187205 if (!videoTracks .isEmpty ()) {
188206 videoTrack = videoTracks .get (0 );
189207 }
190- }
191208
192- if (videoTrack == null ) {
193- Log .w (TAG , "No video stream for react tag: " + streamURL );
194- }
195- }
209+ if (videoTrack == null ) {
210+ Log .w (TAG , "No video stream for react tag: " + streamURL );
211+ post (() -> callback .accept (null ));
212+ return ;
213+ }
196214
197- return videoTrack ;
215+ // Post result back to UI thread
216+ final VideoTrack result = videoTrack ;
217+ post (() -> callback .accept (result ));
218+ } catch (Throwable tr ) {
219+ Log .e (TAG , "Error getting video track for stream URL: " + streamURL , tr );
220+ post (() -> callback .accept (null ));
221+ }
222+ });
198223 }
199224
200225 @ Override
@@ -452,20 +477,23 @@ private void setScalingType(ScalingType scalingType) {
452477 * this {@code WebRTCView} or {@code null}.
453478 */
454479 void setStreamURL (String streamURL ) {
455- // Is the value of this.streamURL really changing?
456- if (!Objects .equals (streamURL , this .streamURL )) {
457- // XXX The value of this.streamURL is really changing. Before
458- // realizing/applying the change, let go of the old videoTrack. Of
459- // course, that is only necessary if the value of videoTrack will
460- // really change. Please note though that letting go of the old
461- // videoTrack before assigning to this.streamURL is vital;
462- // otherwise, removeRendererFromVideoTrack will fail to remove the
463- // old videoTrack from the associated videoRenderer, two
464- // VideoTracks (the old and the new) may start rendering and, most
465- // importantly the videoRender may eventually crash when the old
466- // videoTrack is disposed.
467- VideoTrack videoTrack = getVideoTrackForStreamURL (streamURL );
480+ Log .d (TAG , "Set stream URL " + streamURL + " current: " + this .streamURL );
481+ if (Objects .equals (streamURL , this .streamURL )) {
482+ return ;
483+ }
468484
485+ // The value of this.streamURL is really changing. Before
486+ // realizing/applying the change, let go of the old videoTrack. Of
487+ // course, that is only necessary if the value of videoTrack will
488+ // really change. Please note though that letting go of the old
489+ // videoTrack before assigning to this.streamURL is vital;
490+ // otherwise, removeRendererFromVideoTrack will fail to remove the
491+ // old videoTrack from the associated videoRenderer, two
492+ // VideoTracks (the old and the new) may start rendering and, most
493+ // importantly the videoRender may eventually crash when the old
494+ // videoTrack is disposed.
495+ getVideoTrackForStreamURL (streamURL , videoTrack -> {
496+ Log .d (TAG , "Got video track for stream URL " + streamURL + " -> " + videoTrack );
469497 if (this .videoTrack != videoTrack ) {
470498 setVideoTrack (null );
471499 }
@@ -475,7 +503,7 @@ void setStreamURL(String streamURL) {
475503 // After realizing/applying the change in the value of
476504 // this.streamURL, reflect it on the value of videoTrack.
477505 setVideoTrack (videoTrack );
478- }
506+ });
479507 }
480508
481509 /**
0 commit comments