VideoCard class
A stateful widget displaying video participant card with stream rendering, controls, and waveform.
Renders a participant tile showing:
- Video stream via CardVideoDisplay (or MiniCard fallback if no stream)
- Name badge overlay (top-right by default)
- Audio/video toggle buttons (top-left by default)
- Animated waveform bars (9 bars, visible when video off + audio detected)
- Optional mirror mode for local camera
Rendering Logic:
- If customBuilderprovided → delegates full rendering
- Else builds Stack with:
- Background Container (containerBuilder)
- Video display via CardVideoDisplay or MiniCard fallback
- AudioDecibelCheck (monitors audio levels)
- Waveform overlay (overlayBuilder → waveformBuilder)
- Name badge (infoBuilder)
- Control buttons (audio/video toggles)
 
Layout Structure:
Stack (wrapperBuilder)
  ├─ Positioned.fill → Container (containerBuilder)
  │  └─ IF videoStream != null:
  │     └─ CardVideoDisplay (video stream)
  │     ELSE:
  │     └─ MiniCard (avatar fallback)
  ├─ AudioDecibelCheck (monitors audio, updates waveform state)
  ├─ IF showWaveform:
  │  └─ Positioned.fill → Container (overlayBuilder)
  │     └─ Row (waveformBuilder)
  │        └─ 9 × AnimatedContainer (bars)
  ├─ Positioned (infoPosition) → Container (infoBuilder)
  │  └─ Row (nameBadge + waveform indicator)
  └─ Positioned (controlsPosition) → Row
     ├─ GestureDetector (audio toggle)
     └─ GestureDetector (video toggle)
Video Stream Rendering:
- Uses CardVideoDisplayto render MediaStream via WebRTC RTCVideoRenderer
- Applies mirror mode if doMirror=true(CSS scaleX(-1))
- Falls back to MiniCard avatar if videoStreamnull or video track unavailable
- Respects forceFullDisplayfor aspect ratio handling
Audio Level Detection:
- AudioDecibelCheckcomponent polls- parameters.audioDecibelsevery 2 seconds
- Matches by participant.nameagainstaudioDecibels[i].name
- Updates showWaveformstate based on:- Participant unmuted (participant.muted == false)
- Audio detected (avgAudioDecibels > threshold)
- Video off or !forceFullDisplay
 
- Participant unmuted (
- Triggers waveform animation via AnimationControllers
Control Button Workflow:
- 
Audio Toggle (Mute/Unmute): - Taps mute icon in controls overlay
- Calls toggleAudio()→controlUserMedia
- Parameters: { participantId, participantName, type: 'audio' }
- Checks permissions (host/coHost with 'media' permission)
- Emits socket event 'controlMedia'to server
 
- 
Video Toggle (On/Off): - Taps video icon in controls overlay
- Calls toggleVideo()→controlUserMedia
- Parameters: { participantId, participantName, type: 'video' }
- Checks permissions (host/coHost with 'media' permission)
- Emits socket event 'controlMedia'to server
 
Waveform Animation:
- State creates 9 AnimationControllers (1 per bar)
- animateWaveform()starts repeat(reverse: true) animation
- resetWaveform()stops/resets all controllers
- Bar heights scale from 1px (silent) to 40px (loud)
- Bars hidden if participant muted or no audio detected
- Disposed on widget unmount
Builder Hook Priorities:
- customBuilder→ full widget replacement (ignores all other props)
- wrapperBuilder→ wraps Stack; receives stackChildren + default
- containerBuilder→ wraps video/avatar container; receives child + default
- infoBuilder→ wraps name badge/waveform; receives nameBadge + waveform + default
- overlayBuilder→ wraps waveform overlay; receives waveform + default
- waveformBuilder→ wraps bars; receives animationControllers + default
Common Use Cases:
- 
Grid View with Videos: GridView.builder( itemCount: videoParticipants.length, itemBuilder: (context, index) { final participant = videoParticipants[index]; return VideoCard( options: VideoCardOptions( parameters: parameters, name: participant.name, remoteProducerId: participant.videoID, eventType: EventType.conference, videoStream: participant.stream, participant: participant, ), ); }, )
- 
Local Camera Preview: VideoCard( options: VideoCardOptions( parameters: parameters, name: 'You', remoteProducerId: 'local', eventType: EventType.conference, videoStream: localStream, participant: localParticipant, doMirror: true, controlsPosition: 'bottomRight', ), )
- 
Host-Only Controls: VideoCard( options: VideoCardOptions( parameters: parameters, name: 'John Doe', remoteProducerId: 'producer-123', eventType: EventType.conference, videoStream: mediaStream, participant: participant, showControls: isHost, videoControlsComponent: isHost ? hostControls : null, ), )
- 
Custom Name Badge with Status: VideoCard( options: VideoCardOptions( parameters: parameters, name: 'John Doe', remoteProducerId: 'producer-123', eventType: EventType.conference, videoStream: mediaStream, participant: participant, infoBuilder: (context, nameBadge, waveform, defaultInfo) { return Stack( children: [ defaultInfo, Positioned( bottom: 0, right: 0, child: Icon(Icons.fiber_manual_record, color: Colors.green, size: 12), ), ], ); }, ), )
Override Integration:
Integrates with MediasfuUICustomOverrides for global styling:
overrides: MediasfuUICustomOverrides(
  videoCardOptions: ComponentOverride<VideoCardOptions>(
    builder: (existingOptions) => VideoCardOptions(
      parameters: existingOptions.parameters,
      name: existingOptions.name,
      remoteProducerId: existingOptions.remoteProducerId,
      eventType: existingOptions.eventType,
      videoStream: existingOptions.videoStream,
      participant: existingOptions.participant,
      containerDecoration: BoxDecoration(
        gradient: LinearGradient(colors: [Colors.blue, Colors.purple]),
        borderRadius: BorderRadius.circular(16),
      ),
      barColor: Colors.yellow,
      nameTextStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
    ),
  ),
),
Performance Notes:
- Animation controllers created once in initState (9 controllers)
- Audio level polling every 2 seconds (not every frame)
- Waveform hidden when video active (skips rendering 9 bars)
- Video rendering delegated to CardVideoDisplay (uses RTCVideoRenderer)
- Disposed controllers + video renderer cleaned up in dispose()
Permission Requirements:
- Controlling others requires host or coHost with 'media' permission
- Self-control always allowed
- Socket connection required for remote control actions
Mirror Mode:
- Applied via CSS transform: scaleX(-1) on video element
- Typically used for local camera to match user expectation
- Does not affect stream data, only display
- Inheritance
- 
    - Object
- DiagnosticableTree
- Widget
- StatefulWidget
- VideoCard
 
Constructors
- VideoCard({Key? key, required VideoCardOptions options})
- 
          
            const
Properties
- hashCode → int
- 
  The hash code for this object.
  no setterinherited
- key → Key?
- 
  Controls how one widget replaces another widget in the tree.
  finalinherited
- options → VideoCardOptions
- 
  
  final
- runtimeType → Type
- 
  A representation of the runtime type of the object.
  no setterinherited
Methods
- 
  createElement() → StatefulElement 
- 
  Creates a StatefulElement to manage this widget's location in the tree.
  inherited
- 
  createState() → _VideoCardState 
- 
  Creates the mutable state for this widget at a given location in the tree.
  override
- 
  debugDescribeChildren() → List< DiagnosticsNode> 
- 
  Returns a list of DiagnosticsNode objects describing this node's
children.
  inherited
- 
  debugFillProperties(DiagnosticPropertiesBuilder properties) → void 
- 
  Add additional properties associated with the node.
  inherited
- 
  noSuchMethod(Invocation invocation) → dynamic 
- 
  Invoked when a nonexistent method or property is accessed.
  inherited
- 
  toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode 
- 
  Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
  inherited
- 
  toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) → String 
- 
  A string representation of this object.
  inherited
- 
  toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String 
- 
  Returns a string representation of this node and its descendants.
  inherited
- 
  toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String 
- 
  Returns a one-line detailed description of the object.
  inherited
- 
  toStringShort() → String 
- 
  A short, textual description of this widget.
  inherited
Operators
- 
  operator ==(Object other) → bool 
- 
  The equality operator.
  inherited