Skip to content

GUI Room example app. - #600

Open
cloudwebrtc wants to merge 5 commits into
mainfrom
duan/wxpy-room-example-app
Open

GUI Room example app.#600
cloudwebrtc wants to merge 5 commits into
mainfrom
duan/wxpy-room-example-app

Conversation

@cloudwebrtc

Copy link
Copy Markdown
Contributor

This is a room example app written in wxPython, used to test the basic functionality of the Python SDK.

usage:

pip3 install wxPython
python3 examples/wxpy_room/wxpy_room.py 
dea57907052de50d3e4e3f15c1917704
devin-ai-integration[bot]

This comment was marked as resolved.

cloudwebrtc and others added 2 commits April 8, 2026 15:24
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 4 new potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review
Comment on lines +134 to +136
if self._test_video_task and not self._test_video_task.cancelled():
self._test_video_task.cancel()
return False

@devin-ai-integration devin-ai-integration Bot Apr 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 toggle_test_video/toggle_test_audio permanently stuck after task completes due to error

The toggle methods use not self._test_video_task.cancelled() to decide whether the task is still active. asyncio.run_coroutine_threadsafe returns a concurrent.futures.Future. After the coroutine completes due to an error (e.g., publish fails because room disconnected), the future is in FINISHED state — cancelled() returns False and done() returns True. Subsequent calls to toggle_test_video() always enter the "stop" branch at line 169, call cancel() on the already-finished future (which returns False and does nothing), and return False. The user can never start a new test video/audio until reconnecting. The fix is to use .done() instead of .cancelled() to check if the task has already completed.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +198 to +200
if self._test_audio_task and not self._test_audio_task.cancelled():
self._test_audio_task.cancel()
return False

@devin-ai-integration devin-ai-integration Bot Apr 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 toggle_test_audio has same stuck-after-error bug as toggle_test_video

Same issue as the video toggle: toggle_test_audio uses not self._test_audio_task.cancelled() at line 233, which becomes permanently stuck after the audio publishing task completes due to an error. Should use .done() instead.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +388 to +396
def _on_local_track_unpublished(self, publication):
logger.info("Local track unpublished: %s", publication.sid)
identity = self.room.local_participant.identity
track_sid = publication.sid
self._track_to_participant.pop(track_sid, None)
stream = self._video_streams.pop(identity, None)
if stream:
asyncio.ensure_future(stream.aclose())
self._post_participants()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 _on_local_track_unpublished unconditionally removes video stream regardless of track kind

When any local track is unpublished (including audio), the handler at line 393 unconditionally pops from self._video_streams for the local participant identity. If the user has both test video and test audio publishing, stopping the audio track triggers _on_local_track_unpublished, which incorrectly closes the video stream. Compare with _on_local_track_published at examples/wxpy_room/wxpy_room.py:376 which correctly checks track.kind == rtc.TrackKind.KIND_VIDEO. The unpublish handler should similarly check publication.kind (available via TrackPublication.kind at livekit-rtc/livekit/rtc/track_publication.py:44) before removing the video stream.

Suggested change
def _on_local_track_unpublished(self, publication):
logger.info("Local track unpublished: %s", publication.sid)
identity = self.room.local_participant.identity
track_sid = publication.sid
self._track_to_participant.pop(track_sid, None)
stream = self._video_streams.pop(identity, None)
if stream:
asyncio.ensure_future(stream.aclose())
self._post_participants()
def _on_local_track_unpublished(self, publication):
logger.info("Local track unpublished: %s", publication.sid)
identity = self.room.local_participant.identity
track_sid = publication.sid
self._track_to_participant.pop(track_sid, None)
if publication.kind == rtc.TrackKind.KIND_VIDEO:
stream = self._video_streams.pop(identity, None)
if stream:
asyncio.ensure_future(stream.aclose())
self._post_participants()
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +311 to +312
except Exception as e:
self._post_state("error", str(e))

@devin-ai-integration devin-ai-integration Bot Apr 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Event loop thread leaked forever on connection error

When _async_connect catches a connection error at line 311, it posts an "error" state but the coroutine returns normally. The caller _run_loop at line 276 then calls self.loop.run_forever(), which blocks forever since nothing ever calls loop.stop(). The wx-side error handler at line 1111 creates a new RoomManager, orphaning the old thread and event loop. Each failed connection attempt leaks a daemon thread.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant