Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 97 additions & 16 deletions dogfooding/lib/screens/call_stats_screen.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_dogfooding/app/user_auth_controller.dart';
import 'package:flutter_dogfooding/di/injector.dart';
import 'package:flutter_dogfooding/screens/stats_latency_chart.dart';
import 'package:flutter_dogfooding/screens/stats_battery_chart.dart';
import 'package:flutter_dogfooding/screens/stats_thermal_chart.dart';
import 'package:flutter_dogfooding/theme/app_palette.dart';
import 'package:stream_video_flutter/stream_video_flutter.dart';

Expand All @@ -21,12 +25,23 @@ class CallStatsScreen extends StatelessWidget {
final textTheme = streamVideoTheme.textTheme;
final currentUser = _userAuthController.currentUser;

return StreamBuilder<CallState>(
stream: call.state.asStream(),
return StreamBuilder<CallMetrics?>(
stream: call.statsReporter?.stream,
initialData: call.statsReporter?.currentMetrics,
builder: (context, snapshot) {
final state = snapshot.data;
final subscriberBitrate = state?.subscriberStats?.bitrateKbps;
final publisherBitrate = state?.publisherStats?.bitrateKbps;

if (state == null) {
return const Center(
child: CircularProgressIndicator(),
);
}

final subscriberBitrate = state.subscriber?.bitrateKbps;
final publisherBitrate = state.publisher?.bitrateKbps;

final batteryDrained = (state.initialBatteryLevel ?? 0) -
(state.batteryLevelHistory.lastOrNull ?? 0);

return SafeArea(
top: false,
Expand Down Expand Up @@ -93,9 +108,75 @@ class CallStatsScreen extends StatelessWidget {
SizedBox(
height: 200,
child: StatsLatencyChart(
latencyHistory: state!.latencyHistory,
latencyHistory: state.latencyHistory,
),
),
const SizedBox(
height: 16,
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
const Icon(Icons.whatshot, color: Colors.white),
const SizedBox(width: 8),
Text(
'Thermal state',
style:
textTheme.title3.apply(color: Colors.white),
),
],
),
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'Device thermal state history. Higher bars indicate more severe states.',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(height: 16),
SizedBox(
height: 200,
child: StatsThermalChart(
thermalSeverityHistory: state.thermalStatusHistory,
),
),
const SizedBox(
height: 16,
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
const Icon(Icons.battery_full, color: Colors.white),
const SizedBox(width: 8),
Text(
'Battery level',
style:
textTheme.title3.apply(color: Colors.white),
),
],
),
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'Track device battery level throughout the call.',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(height: 16),
SizedBox(
height: 200,
child: StatsBatteryChart(
batteryLevelHistory: state.batteryLevelHistory,
),
),
Text(
'Battery percentage consumed during call: $batteryDrained%',
style: const TextStyle(color: Colors.white),
),
const SizedBox(
height: 16,
),
Expand Down Expand Up @@ -128,7 +209,7 @@ class CallStatsScreen extends StatelessWidget {
Expanded(
child: LatencyOrJitterItem(
title: 'Latency',
value: state.publisherStats?.latency ?? 0,
value: state.publisher?.latency ?? 0,
),
),
],
Expand All @@ -138,13 +219,13 @@ class CallStatsScreen extends StatelessWidget {
Expanded(
child: LatencyOrJitterItem(
title: 'Receive jitter',
value: state.subscriberStats?.jitterInMs,
value: state.subscriber?.jitterInMs,
),
),
Expanded(
child: LatencyOrJitterItem(
title: 'Publish jitter',
value: state.publisherStats?.jitterInMs,
value: state.publisher?.jitterInMs,
),
),
],
Expand All @@ -156,15 +237,15 @@ class CallStatsScreen extends StatelessWidget {
title: 'Publish bitrate',
value: publisherBitrate == null
? '--'
: '${state.publisherStats?.bitrateKbps} Kbps',
: '${state.publisher?.bitrateKbps} Kbps',
),
),
Expanded(
child: StatsItem(
title: 'Receive bitrate',
value: subscriberBitrate == null
? '--'
: '${state.subscriberStats?.bitrateKbps} Kbps',
: '${state.subscriber?.bitrateKbps} Kbps',
),
),
],
Expand All @@ -175,29 +256,29 @@ class CallStatsScreen extends StatelessWidget {
child: StatsItem(
title: 'Publish resolution',
value:
"${state.publisherStats?.resolution} | ${state.publisherStats?.videoCodec?.join('+')}",
"${state.publisher?.resolution} | ${state.publisher?.videoCodec?.join('+')}",
),
),
Expanded(
child: StatsItem(
title: 'Reveive resolution',
title: 'Receive resolution',
value:
"${state.subscriberStats?.resolution} | ${state.subscriberStats?.videoCodec?.join('+')}",
"${state.subscriber?.resolution} | ${state.subscriber?.videoCodec?.join('+')}",
),
),
],
),
StatsItem(
title: 'Region',
value: state.localStats?.sfu,
value: state.clientEnvironment.sfu,
),
StatsItem(
title: 'SDK Version',
value: state.localStats?.sdkVersion,
value: state.clientEnvironment.sdkVersion,
),
StatsItem(
title: 'WebRTC Version',
value: state.localStats?.webRtcVersion,
value: state.clientEnvironment.webRtcVersion,
),
]
],
Expand Down
118 changes: 118 additions & 0 deletions dogfooding/lib/screens/stats_battery_chart.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter_dogfooding/theme/app_palette.dart';

class StatsBatteryChart extends StatelessWidget {
const StatsBatteryChart({super.key, required this.batteryLevelHistory});

final List<int> batteryLevelHistory;

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: LineChart(
LineChartData(
lineTouchData: const LineTouchData(enabled: false),
gridData: FlGridData(
show: true,
drawVerticalLine: false,
drawHorizontalLine: true,
verticalInterval: 1,
horizontalInterval: 20,
getDrawingVerticalLine: (value) {
return const FlLine(
color: Color(0xff37434d),
strokeWidth: 1,
);
},
getDrawingHorizontalLine: (value) {
return const FlLine(
color: Color(0xff37434d),
strokeWidth: 1,
);
},
),
titlesData: FlTitlesData(
show: true,
rightTitles: const AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 40,
interval: 20,
),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
leftTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
),
borderData: FlBorderData(
show: false,
),
minX: 0,
maxX: 20,
minY: 0,
maxY: 100,
lineBarsData: [
LineChartBarData(
spots: batteryLevelHistory.indexed
.map<FlSpot>(
(m) => FlSpot(m.$1.toDouble(), m.$2.toDouble()),
)
.toList(),
isCurved: true,
gradient: LinearGradient(
colors: [
ColorTween(
begin: AppColorPalette.appGreen,
// ignore: deprecated_member_use
end: AppColorPalette.appGreen.withOpacity(0.5))
.lerp(0.2)!,
ColorTween(
begin: AppColorPalette.appGreen,
// ignore: deprecated_member_use
end: AppColorPalette.appGreen.withOpacity(0.5))
.lerp(0.2)!,
],
),
barWidth: 3,
isStrokeCapRound: true,
dotData: const FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [
ColorTween(
begin: AppColorPalette.appGreen,
end:
// ignore: deprecated_member_use
AppColorPalette.appGreen.withOpacity(0.5))
.lerp(0.2)!
// ignore: deprecated_member_use
.withOpacity(0.1),
ColorTween(
begin: AppColorPalette.appGreen,
end:
// ignore: deprecated_member_use
AppColorPalette.appGreen.withOpacity(0.5))
.lerp(0.2)!
// ignore: deprecated_member_use
.withOpacity(0.1),
],
),
),
),
],
),
),
);
}
}
Loading