Open lurongshuang opened 1 day ago
___lldb_unnamed_symbol3992 + 180 WebRTC
___lldb_unnamed_symbol3992:
-> 0x1056fef60 <+180>: stp q0, q1, [x2]
0x1056fef64 <+184>: add x10, x2, x3
0x1056fef68 <+188>: stp q2, q3, [x10]
0x1056fef6c <+192>: add x2, x10, x3
Target 0: (Runner) stopped.ios 16.7.10 Iphone X
`import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:livekit_client/livekit_client.dart';
import 'no_video.dart'; import 'participant_info.dart';
abstract class ParticipantWidget extends StatefulWidget { // Convenience method to return relevant widget for participant static ParticipantWidget widgetFor(ParticipantTrack participantTrack, {bool showStatsLayer = false, Widget? noVideoWidget, Key? key}) { if (participantTrack.participant is LocalParticipant) { return LocalParticipantWidget( participantTrack.participant as LocalParticipant, participantTrack.type, showStatsLayer, noVideoWidget: noVideoWidget, key: key); } else if (participantTrack.participant is RemoteParticipant) { return RemoteParticipantWidget( participantTrack.participant as RemoteParticipant, participantTrack.type, showStatsLayer, noVideoWidget: noVideoWidget, key: key); } throw UnimplementedError('Unknown participant type'); }
// Must be implemented by child class abstract final Participant participant; abstract final ParticipantTrackType type; abstract final bool showStatsLayer; final VideoQuality quality; abstract final Widget? noVideoWidget;
const ParticipantWidget({this.quality = VideoQuality.MEDIUM, super.key}); }
class LocalParticipantWidget extends ParticipantWidget { @override final LocalParticipant participant; @override final ParticipantTrackType type; @override final bool showStatsLayer; @override final Widget? noVideoWidget;
const LocalParticipantWidget( this.participant, this.type, this.showStatsLayer, { this.noVideoWidget, super.key, });
@override
State
class RemoteParticipantWidget extends ParticipantWidget { @override final RemoteParticipant participant; @override final ParticipantTrackType type; @override final bool showStatsLayer;
@override final Widget? noVideoWidget;
const RemoteParticipantWidget( this.participant, this.type, this.showStatsLayer, {this.noVideoWidget, super.key});
@override
State
abstract class _ParticipantWidgetState
VideoTrack? get activeVideoTrack;
AudioTrack? get activeAudioTrack;
TrackPublication? get videoPublication;
TrackPublication? get audioPublication;
bool get isScreenShare => widget.type == ParticipantTrackType.kScreenShare;
EventsListener
@override
void initState() {
super.initState();
_listener = widget.participant.createListener();
_listener?.on
widget.participant.addListener(_onParticipantChanged);
_onParticipantChanged();
}
@override void dispose() { widget.participant.removeListener(_onParticipantChanged); _listener?.dispose(); super.dispose(); }
@override void didUpdateWidget(covariant T oldWidget) { oldWidget.participant.removeListener(_onParticipantChanged); widget.participant.addListener(_onParticipantChanged); _onParticipantChanged(); super.didUpdateWidget(oldWidget); }
// Notify Flutter that UI re-build is required, but we don't set anything here // since the updated values are computed properties. void _onParticipantChanged() => setState(() {});
// Widgets to show above the info bar
List
@override Widget build(BuildContext ctx) { return activeVideoTrack != null && !activeVideoTrack!.muted ? VideoTrackRenderer( renderMode: VideoRenderMode.auto, activeVideoTrack!, fit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover) : widget.noVideoWidget ?? const NoVideoWidget(); } // Container( // foregroundDecoration: BoxDecoration( // border: widget.participant.isSpeaking && !isScreenShare // ? Border.all( // width: 5, // color: TCS.darkBackground, // ) // : null, // ), // decoration: BoxDecoration( // color: Theme.of(ctx).cardColor, // ), // child: Stack(children: [ // Video // InkWell( // onTap: () => setState(() => _visible = !_visible), // child: activeVideoTrack != null && !activeVideoTrack!.muted // ? VideoTrackRenderer( // renderMode: VideoRenderMode.auto, // activeVideoTrack!, // fit: RTCVideoViewObjectFit.RTCVideoViewObjectFitContain) // : const NoVideoWidget()), // Bottom bar // Align( // alignment: Alignment.topRight, // child: Column( // crossAxisAlignment: CrossAxisAlignment.stretch, // mainAxisSize: MainAxisSize.min, // children: [ // ParticipantInfoWidget( // title: widget.participant.name.isNotEmpty // ? '${widget.participant.name} (${widget.participant.identity})' // : widget.participant.identity, // audioAvailable: audioPublication?.muted == false && // audioPublication?.subscribed == true, // connectionQuality: widget.participant.connectionQuality, // isScreenShare: isScreenShare, // enabledE2EE: widget.participant.isEncrypted) // ])), // if (widget.showStatsLayer) // Positioned( // top: 30.r, // left: 5.r, // child: ParticipantStatsWidget(participant: widget.participant)), // ...extraWidgets(isScreenShare) // ])); }
class _LocalParticipantWidgetState
extends _ParticipantWidgetState
@override
LocalTrackPublication
@override VideoTrack? get activeVideoTrack => videoPublication?.track;
@override AudioTrack? get activeAudioTrack => audioPublication?.track; }
class _RemoteParticipantWidgetState
extends _ParticipantWidgetState
@override
RemoteTrackPublication
@override VideoTrack? get activeVideoTrack => videoPublication?.track;
@override AudioTrack? get activeAudioTrack => audioPublication?.track;
@override
List
class RemoteTrackPublicationMenuWidget extends StatelessWidget { final IconData icon; final RemoteTrackPublication pub;
const RemoteTrackPublicationMenuWidget({ required this.pub, required this.icon, super.key, });
@override
Widget build(BuildContext context) => Material(
color: Colors.black.withOpacity(0.3),
child: PopupMenuButton
class RemoteTrackFPSMenuWidget extends StatelessWidget { final IconData icon; final RemoteTrackPublication pub;
const RemoteTrackFPSMenuWidget({ required this.pub, required this.icon, super.key, });
@override
Widget build(BuildContext context) => Material(
color: Colors.black.withOpacity(0.3),
child: PopupMenuButton
class RemoteTrackQualityMenuWidget extends StatelessWidget { final IconData icon; final RemoteTrackPublication pub;
const RemoteTrackQualityMenuWidget({ required this.pub, required this.icon, super.key, });
@override
Widget build(BuildContext context) => Material(
color: Colors.black.withOpacity(0.3),
child: PopupMenuButton
` Widget getLocalFullScreen(bool isLocal, {Widget? noVideoWidget, Key? key}) { if (isLocal) { if (_room == null || _room!.localParticipant == null) { return noVideoWidget ?? const NoVideoWidget(); } return ParticipantWidget.widgetFor( ParticipantTrack(participant: _room!.localParticipant!), noVideoWidget: noVideoWidget, key: key); }
if (participantTracks.isEmpty) {
return noVideoWidget ?? const NoVideoWidget();
}
return ParticipantWidget.widgetFor(participantTracks.first,
noVideoWidget: noVideoWidget, key: key);
}`
During the switching process, the frame rate kept decreasing, causing the screen to lag
Describe the bug In the floating window function, local or remote images will be repeatedly obtained and given to different parent widgets. When obtaining multiple times, the view will freeze.
[✓] Flutter (Channel stable, 3.24.3, on macOS 15.1.1 24B91 darwin-arm64, locale zh-Hans-CN) [!] Android toolchain - develop for Android devices (Android SDK version 34.0.0) Android Studio (version 2024.1) Xcode - develop for iOS and macOS (Xcode 16.0)