Whenever I try to attempt to connect in the server using websocket, it throws and error that says: Websocket error: WebsocketChannelException: WebSocketException: Connection to 'http://host:port/v2/ws-tracking?first_query=first_value&second_query=second_value# was not upgraded to websocket'.
The server side uses FastAPI as a backend and the router is configured as a websocket. Additionally, this is running on our GCP VM instance as a docker container so I am not sure if there seems to be a problem with the cloud server we are hosting it in.
This is the code block for our flutter mobile app:
import 'package:flutter/material.dart';
import 'package:lifttrack/cam/preview.dart';
import 'package:video_player/video_player.dart';
import 'package:image_picker/image_picker.dart';
import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter/return_code.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:web_socket_channel/io.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'dart:io';
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import '../services/api_services.dart'; // a module
class VideoPage extends StatefulWidget {
final String exerciseType;
const VideoPage({required this.exerciseType, super.key});
@override
_VideoPageState createState() => _VideoPageState();
}
class _VideoPageState extends State<VideoPage> {
VideoPlayerController? _controller;
File? _videoFile;
final ImagePicker _picker = ImagePicker();
IOWebSocketChannel? _channel;
final List<Map<String, dynamic>> _annotatedFrames = [];
final FlutterTts _flutterTts = FlutterTts();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_connectWebSocket();
});
}
Future<void> _connectWebSocket() async {
try {
// Use cached user data if available
final user = await ApiService().getCurrentUser();
final username = user.userName;
// Construct WebSocket URL with username and exercise_name as query parameters
final uri = Uri(
scheme: 'ws', // Use 'wss' for secure connections in production
host: 'x.x.x.x', // Assume the host exist
port: xxxx, // Assume is a valid port
path: '/v2/ws-tracking', // ws endpoint from the FastAPI backend
queryParameters: {
'username': username,
'exercise_name': widget.exerciseType,
},
);
final wsUrl = uri.toString();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Connecting to WebSocket...')),
);
_channel = IOWebSocketChannel.connect(wsUrl);
_channel?.stream.listen((dynamic data) async {
if (data != null) {
try {
if (data is String) {
final decodedData = jsonDecode(data);
if (decodedData is Map && decodedData['type'] == 'analysis') {
final accuracy = decodedData['accuracy'];
final suggestions = decodedData['suggestions'];
final predictedClass = decodedData['predicted_class'];
// Enhanced TTS feedback
await _speakAnalysisFeedback(accuracy, suggestions, predictedClass);
// Additional TTS for immediate feedback
await _flutterTts.speak("Starting analysis. Please wait...");
}
} else if (data is Uint8List) {
// Handle binary frame data
setState(() {
_annotatedFrames.add({
'timestamp': DateTime.now().millisecondsSinceEpoch,
'image': data,
});
});
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error processing received data: $e')),
);
}
}
}, onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('WebSocket error: $error')),
);
}, onDone: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('WebSocket connection closed by server')),
);
});
} catch (error) {
if (error is UnauthorizedException) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Session Expired'),
content: Text('Session expired. Please log in again.'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamedAndRemoveUntil(
'/login',
(route) => false,
);
},
child: Text('OK'),
),
],
);
},
);
return;
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('WebSocket connection failed: $error')),
);
}
}
}
Currently, I tried to force the connection by adding a header to upgrade the protocol. But hoping to find a permanent solution to this problem. Badly need this project to be finished because this is our thesis.