AudioCard class

A stateful widget displaying audio-only participant card with animated waveform and controls.

Renders a participant tile showing:

  • MiniCard avatar (image or initials)
  • Animated waveform bars (9 bars, height based on audio levels)
  • Name badge overlay (top-right by default)
  • Mute toggle button (top-left by default)

Rendering Logic:

  1. If customBuilder provided → delegates full rendering
  2. Else builds Stack with:
    • Background Container (containerBuilder)
    • Waveform overlay (overlayBuilder → waveformBuilder)
    • Name badge (infoBuilder)
    • Mute button (if showControls=true)

Layout Structure:

Stack (wrapperBuilder)
  ├─ Positioned.fill → Container (containerBuilder)
  │  └─ MiniCard (avatar)
  ├─ Positioned.fill → Container (overlayBuilder)
  │  └─ Row (waveformBuilder)
  │     └─ 9 × AnimatedContainer (bars)
  ├─ Positioned (infoPosition) → Container (infoBuilder)
  │  └─ Text (name badge)
  └─ Positioned (controlsPosition) → GestureDetector
     └─ Icon (mute button)

Audio Level Detection:

  • Reads parameters.audioDecibels list to find participant's audio level
  • Matches by participant.name against audioDecibels[i].name
  • Hides waveform if participant muted (participant.muted == true)
  • Animates bar heights based on detected audio level (0-127 range)

Mute Control Workflow:

  1. User taps mute button (visible if showControls=true)
  2. Calls controlUserMedia function with:
    • participantId: participant.id (socket ID)
    • participantName: participant.name
    • type: 'audio' (media type)
  3. controlMedia checks permissions:
    • Host (islevel='2') → always allowed
    • CoHost with 'media' permission → allowed
    • Self-mute → always allowed
  4. Emits socket event 'controlMedia' to server:
    {
      "participantId": "abc123",
      "participantName": "John Doe",
      "type": "audio"
    }
    
  5. Server broadcasts mute action to all clients

Waveform Animation:

  • State creates 9 AnimationControllers (1 per bar)
  • Effect hook polls parameters.audioDecibels every 2 seconds
  • Updates bar heights via setState → triggers animations
  • Bars scale from 1px (silent) to 40px (loud)
  • Disposed on widget unmount

Builder Hook Priorities:

  • customBuilder → full widget replacement (ignores all other props)
  • wrapperBuilder → wraps Stack; receives stackChildren + default
  • containerBuilder → wraps MiniCard container; receives child + default
  • infoBuilder → wraps name badge; receives overlay + default
  • overlayBuilder → wraps waveform; receives waveform + default
  • waveformBuilder → wraps bars; receives animationControllers + default

Common Use Cases:

  1. Basic Grid Display:

    GridView.builder(
      itemCount: audioParticipants.length,
      itemBuilder: (context, index) {
        final participant = audioParticipants[index];
        return AudioCard(
          options: AudioCardOptions(
            name: participant.name,
            participant: participant,
            parameters: parameters,
            customStyle: BoxDecoration(color: Colors.grey[800]),
          ),
        );
      },
    )
    
  2. Custom Controls Overlay:

    AudioCard(
      options: AudioCardOptions(
        name: 'John Doe',
        participant: participant,
        parameters: parameters,
        videoControlsComponent: Row(
          children: [
            IconButton(icon: Icon(Icons.mic_off), onPressed: muteAction),
            IconButton(icon: Icon(Icons.more_vert), onPressed: showMenu),
          ],
        ),
      ),
    )
    
  3. Silent Display (No Controls):

    AudioCard(
      options: AudioCardOptions(
        name: 'John Doe',
        participant: participant,
        parameters: parameters,
        showControls: false,
        showInfo: false,
      ),
    )
    

Override Integration: Integrates with MediasfuUICustomOverrides for global styling:

overrides: MediasfuUICustomOverrides(
  audioCardOptions: ComponentOverride<AudioCardOptions>(
    builder: (existingOptions) => AudioCardOptions(
      name: existingOptions.name,
      participant: existingOptions.participant,
      parameters: existingOptions.parameters,
      customStyle: BoxDecoration(
        gradient: LinearGradient(colors: [Colors.deepPurple, Colors.purple]),
        borderRadius: BorderRadius.circular(12),
      ),
      barColor: Colors.pink,
    ),
  ),
),

Performance Notes:

  • Animation controllers created once in initState
  • Audio level polling every 2 seconds (not every frame)
  • Waveform hidden if participant muted (skips rendering 9 bars)
  • Disposed controllers cleaned up in dispose()

Permission Requirements:

  • Muting others requires host or coHost with 'media' permission
  • Self-mute always allowed
  • Socket connection required for remote mute actions
Inheritance

Constructors

AudioCard({Key? key, required AudioCardOptions 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 AudioCardOptions
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() → _AudioCardState
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