Connection Unstable

When a participant's network connection becomes unstable, you can provide visual feedback in two ways: warning users when their connection quality degrades, and showing a reconnecting indicator when the connection drops entirely.

Poor Connection Quality Warning

As described in the Network Quality Indicator guide, each participant's connection quality is available through the connectionQuality property on CallParticipantState.

The connection quality can have the following values:

enum SfuConnectionQuality {
  unspecified,
  poor,
  good,
  excellent,
}

To warn the local participant when their connection is poor, you can build a custom participant widget that overlays a notification banner:

class ConnectionAwareParticipant extends StatelessWidget {
  const ConnectionAwareParticipant({
    super.key,
    required this.call,
    required this.participant,
  });

  final Call call;
  final CallParticipantState participant;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        StreamCallParticipant(
          call: call,
          participant: participant,
        ),
        if (participant.isLocal &&
            participant.connectionQuality == SfuConnectionQuality.poor)
          Positioned(
            left: 0,
            right: 0,
            bottom: 0,
            child: Container(
              color: Colors.orange.shade400.withValues(alpha: .85),
              padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
              child: const Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Icon(Icons.signal_wifi_bad, color: Colors.white, size: 16),
                  SizedBox(width: 8),
                  Text(
                    'Your connection is unstable',
                    style: TextStyle(color: Colors.white, fontSize: 12),
                  ),
                ],
              ),
            ),
          ),
      ],
    );
  }
}

Then pass it to StreamCallParticipants via the callParticipantBuilder:

StreamCallContent(
  call: call,
  callParticipantsWidgetBuilder: (context, call) {
    return StreamCallParticipants(
      call: call,
      callParticipantBuilder: (context, call, participant) {
        return ConnectionAwareParticipant(
          call: call,
          participant: participant,
        );
      },
    );
  },
)

Best Practices

  • Only show the warning for SfuConnectionQuality.poor to avoid notification fatigue.
  • Consider showing the banner only for the local participant — they can act on their own connection issues, while other participants' quality indicators are already visible through the network quality indicator.

Reconnection State

When the connection drops entirely, the SDK automatically attempts to reconnect. The reconnection state is available through CallState.status. It transitions to CallStatusReconnecting during reconnection attempts.

You can check for this state using call.state:

final status = call.state.value.status;
if (status.isReconnecting) {
  // Connection dropped, SDK is reconnecting
}

Listening to Reconnection State

To reactively rebuild your UI when the reconnection state changes, use the partialState stream or the PartialCallStateBuilder widget:

PartialCallStateBuilder<CallStatus>(
  call: call,
  selector: (state) => state.status,
  builder: (context, status) {
    if (status.isReconnecting) {
      return const Center(child: Text('Reconnecting...'));
    }
    return const SizedBox.shrink();
  },
)

Displaying a Reconnecting Overlay

For a better user experience, you can display a full-screen overlay during reconnection. StreamCallContent supports this through the callNotConnectedBuilder and callFastReconnectingOverlayBuilder parameters.

Customizing the Not-Connected View

When the connection is fully lost (non-fast reconnect), StreamCallContent shows a fallback view. You can customize it with callNotConnectedBuilder:

StreamCallContent(
  call: call,
  callNotConnectedBuilder: (context, properties) {
    if (properties.isReconnecting) {
      return Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const CircularProgressIndicator(color: Colors.white),
            const SizedBox(height: 16),
            Text(
              'Reconnecting to call...',
              style: Theme.of(context)
                  .textTheme
                  .titleMedium
                  ?.copyWith(color: Colors.white),
            ),
          ],
        ),
      );
    }
    return const Center(
      child: CircularProgressIndicator(),
    );
  },
)

Customizing the Fast-Reconnect Overlay

During a fast reconnect (a brief interruption where participants remain visible), a small indicator is shown. You can customize it with callFastReconnectingOverlayBuilder:

StreamCallContent(
  call: call,
  callFastReconnectingOverlayBuilder: (context, properties) {
    return Positioned(
      top: 16,
      left: 0,
      right: 0,
      child: Center(
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          decoration: BoxDecoration(
            color: Colors.orange.shade800,
            borderRadius: BorderRadius.circular(20),
          ),
          child: const Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              SizedBox(
                width: 16,
                height: 16,
                child: CircularProgressIndicator(
                  strokeWidth: 2,
                  color: Colors.white,
                ),
              ),
              SizedBox(width: 8),
              Text(
                'Reconnecting...',
                style: TextStyle(color: Colors.white, fontSize: 13),
              ),
            ],
          ),
        ),
      ),
    );
  },
)

Built-in Support

The SDK's StreamCallContent automatically handles both reconnection states out of the box:

  • During a full reconnect, it displays a centered "Reconnecting" label.
  • During a fast reconnect, it shows a small CircularProgressIndicator in the top-left corner while keeping participants visible.

If you're using the default StreamCallContent, reconnection feedback is handled automatically without any additional configuration.