Add RPC tester interface to example app - #1085
Conversation
This can be used to exercise sending / receiving rpc requests in the example app
| children: [ | ||
| Expanded( | ||
| child: Text( | ||
| entry.topic, | ||
| style: theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold, color: theme.scaffoldBackgroundColor), | ||
| ), | ||
| ), |
There was a problem hiding this comment.
A drive by comment: the colors in this app (besides being out of date) are fairly limited, which makes styling some of these more complicated interfaces fairly challenging.
I think I might make a follow up pull request which updates the example to use the more modern color pallete / logo, and at the same time try to add in some more color scales to make this less annoying.
The RPC tester itself landed on main through #1087, which included a hardened copy of this branch's rpc_test_sheet.dart and the controls.dart wiring. Resolve the add/add conflict by taking main's version, so this branch now carries only follow-up fixes.
Register the method with the room before tracking it, so a method already registered by another component does not leave a phantom card whose unregister button would remove a handler the tester does not own. Cap the per handler invocation log at 200 entries and stop notifying listeners from in flight handlers after disposal.
…ts leave The form field only reads initialValue when its state is created, so a stale selection could outlive its participant and trip the framework assert that the value must be among the items. Key the field by the participant list and validate the selection before sending.
|
Updated this branch to bring it back to life. The tester itself already landed on main through #1087, which included a hardened copy of this file, so the merge resolves to main's version and keeps the original commits in history. On top of that this PR now carries follow-up fixes to the tester: registration is ordered so a method owned by another component can't leave a phantom card, the per handler invocation log is capped, in flight handlers no longer notify after disposal, and the destination dropdown stays valid when the selected participant leaves. |
This comment has been minimized.
This comment has been minimized.
hiroshihorie
left a comment
There was a problem hiding this comment.
Reviewed the follow-up fixes, all good. The original tester landed via #1087.
## What Folds the pending changesets into the 2.10.0 release. Version propagated by `scripts/create_version.dart`, all version checks pass, `.changes/` emptied. ## Changelog * Added: Swift Package Manager support for iOS and macOS. CocoaPods remains fully supported. (#1142) * Added: `ScreenSelectDialog.show` and `Hardware.requestCapturePermission` so apps can start screen share without importing flutter_webrtc (#1147) * Fixed: Compile errors on Dart 3.13 where nullable publish options are no longer promoted across await (#1146) * Fixed: Omit data stream totalLength when size is unknown (#1141) * Fixed: Harden the example RPC tester (#1085) Minor bump driven by the SPM and screen share additions. ## Why now Dart 3.13 (Flutter 3.47 beta, soon stable) fails to compile every published livekit_client, so #1146 needs to ship before 3.47 lands. The screen share helpers unblock livekit/components-flutter#52, which removes the flutter_webrtc pin conflict that downgrades users to livekit_client 2.6.1 (livekit/components-flutter#49). ## After merge Tag `v2.10.0` to publish. First run of the reworked publish workflow from #1140 (tag guard, pin-warning-only validation gate, forced publish). Downstream: components-flutter #52 switches to `livekit_client: ^2.10.0`, then a components release and an agent-starter-flutter bump.
Flutter counterpart of client-sdk-swift #1085, matching its final merged behavior. Builds on #1182. ## Why webrtc-sdk/webrtc#265 (first shipped in `m144.7559.12`) removed the blocking mic permission request from the AudioEngine device. The pre-enable check is now passive: it returns `kAudioEngineErrorInsufficientDevicePermission` (-9000) instead of prompting, so requesting permission is the SDK's job. flutter-webrtc still pins `144.7559.10`, so this is not load-bearing yet. It is harmless there, since `getUserMedia` in flutter-webrtc already prompts and the status is resolved before the device's blocking path runs. Once flutter-webrtc bumps past `.12` and the pin here follows, this is what keeps the current behavior. ## What Flutter already had flutter-webrtc's `getUserMedia` calls `AVCaptureDevice requestAccessForMediaType:` and waits for the answer, so every livekit_client mic path (publish, `restartTrack` on unmute, pre-connect audio) already prompted before the audio device saw the track. That part of #1085 needs no port. #1182 already maps -9000 to `TrackCreateException` for the direct ADM entry points (`setEngineAvailability`, `startLocalRecording`). ## What this adds The one behavior from #1085 that was missing: only prompt while the app can show the alert. - Native `ensureMicrophoneAccess` in `LiveKitPlugin.swift`: `authorized` passes, `denied`/`restricted` fail, `notDetermined` requests access. On iOS the request is only made while `UIApplication.shared.applicationState == .active`. An inactive or backgrounded app (locked screen, CallKit wake, app switcher) has the alert deferred by the system, and awaiting it would suspend `getUserMedia` and the `_publishRunner` behind it, blocking camera and screen share publishes for as long as the app stays there. Failing fast lets the next foreground attempt prompt normally. macOS can present the prompt regardless, so it always requests. No app extension concern here, the plugin is app-only. - The gate is skipped while engine input availability is disabled (`setEngineAvailability`, the CallKit flow), mirroring the same late fix in #1085: the audio device module defers opening input entirely and runs no permission check there, so gating would turn a working background connect into a `deviceAccessDenied` failure. The check reads the plugin's tracked availability value, so it also covers gating done natively before the Flutter engine exists. - `LocalTrack.createStream` calls it for `AudioCaptureOptions` on Apple platforms before `getUserMedia`. That is the Flutter choke point: `LocalAudioTrack.create()`, `restartTrack()` and `PreConnectAudioBuffer.startRecording()` all reach it. Since the prompt in Flutter happens at `getUserMedia` rather than at capture start, the gate sits in front of that instead of in `startCapture` as in Swift. - Failures surface as `TrackCreateException` through the `deviceAccessDenied` code introduced in #1182. - Docs for `withPreConnectAudio` and `PreConnectAudioBuffer.startRecording` now say permission is requested at recording start but only while the app is active, so callers running at app launch should request it up front (matching the final #1085 wording). `Native.setEngineAvailability` documents that permission is not requested there and must be granted before input availability is restored. ## Testing - `flutter analyze`, `flutter test`, `dart format --set-exit-if-changed`, `import_sorter --exit-if-changed` clean. - Unit tests cover `Native.ensureMicrophoneAccess` (no-op when unimplemented, propagates `deviceAccessDenied`). The `createStream` gate is behind `lkPlatformIsApple()` and not reachable from unit tests. - The example app builds for iOS (device SDK) and macOS with the change, re-verified after the rebase onto `main`. On-device run against a fresh install (first-launch prompt) and a CallKit background wake still to do. Refs CLT-3243, client-sdk-swift#1085
Adds a new button on the bottom control bar for the "rpc tester":
When clicked, it opens up a new panel which has two sections:
The top section allows sending RPC messages - select a destination participant, topic, and enter a payload, and click "Send". Note that there are two payload presets -
"hello world"and"X" * 20000to provide some easy to generate data to test some edge cases.The bottom section lets you configure rpc handlers. Enter a rpc handler topic and a static response, and submit. Then when this participant receives a RPC request, the request will be responded to with the static response. This static response also has the same payload presets as the request.
Warning
This pull request was LLM generated and has only been lightly reviewed by a human. The author has tested this and confirms it works in the happy path, but no other validation has been done.
A more thorough review of this needs to occur before it could be merged.