// Singleton import 'dart:async'; import 'package:bus_infotainment/audio_cache.dart'; import 'package:bus_infotainment/tfl_datasets.dart'; import 'package:bus_infotainment/utils/audio%20wrapper.dart'; import 'package:bus_infotainment/utils/delegates.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; class LiveInformation { static final LiveInformation _singleton = LiveInformation._internal(); factory LiveInformation() { return _singleton; } LiveInformation._internal(); Future LoadDatasets() async { { // Load the bus sequences try { http.Response response = await http.get(Uri.parse('https://tfl.gov.uk/bus-sequences.csv')); busSequences = BusSequences.fromCSV(response.body); print("Loaded bus sequences from TFL"); } catch (e) { String csv = await rootBundle.loadString("assets/datasets/bus-sequences.csv"); busSequences = BusSequences.fromCSV(csv); print("Loaded bus sequences from assets"); } } refreshTimer(); } Timer refreshTimer() => Timer.periodic(Duration(seconds: 1), (timer) { _handleAnnouncementQueue(); }); AudioWrapper audioPlayer = AudioWrapper(); AnnouncementCache announcementCache = AnnouncementCache(); List announcementQueue = []; EventDelegate announcementDelegate = EventDelegate(); String CurrentAnnouncement = "*** NO MESSAGE ***"; void _handleAnnouncementQueue() async { print("Handling announcement queue"); if (audioPlayer.state != AudioWrapper_State.Playing) { if (announcementQueue.isNotEmpty) { AnnouncementQueueEntry announcement = announcementQueue.first; announcementDelegate.trigger(announcement); CurrentAnnouncement = announcement.displayText; for (AudioWrapperSource source in announcement.audioSources) { Duration? duration = await audioPlayer.play(source); if (source == announcement.audioSources.last) { announcementQueue.removeAt(0); } await Future.delayed(duration!); await Future.delayed(Duration(milliseconds: 150)); } audioPlayer.stop(); print("Popped announcement queue"); } } } void announceRouteVariant(BusRouteVariant routeVariant) async { if (routeVariant == null) { return; } String display = "${routeVariant.busRoute.routeNumber} to ${routeVariant.busStops.last.formattedStopName}"; String audio_route = "R_${routeVariant.busRoute.routeNumber}_001.mp3"; String audio_destination = routeVariant.busStops.last.getAudioFileName(); print("Audio file: $audio_route"); await announcementCache.loadAnnouncements([audio_route, audio_destination]); AudioWrapperSource source_route = AudioWrapperByteSource(announcementCache[audio_route]); AudioWrapperSource source_destination = AudioWrapperByteSource(announcementCache[audio_destination]); queueAnnouncement(AnnouncementQueueEntry( displayText: display, audioSources: [source_route, AudioWrapperAssetSource("audio/to_destination.wav"), source_destination] )); } late BusSequences busSequences; BusRouteVariant? _currentRouteVariant; void setRouteVariant(BusRouteVariant routeVariant) { _currentRouteVariant = routeVariant; announceRouteVariant(routeVariant); } BusRouteVariant? getRouteVariant() { return _currentRouteVariant; } void queueAnnouncement(AnnouncementQueueEntry announcement) { announcementQueue.add(announcement); } List manualAnnouncements = [ ManualAnnouncementEntry( shortName: "Driver Change", informationText: "Driver Change", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/driverchange.mp3")], ), ManualAnnouncementEntry( shortName: "No Standing Upr Deck", informationText: "No standing on the upper deck", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/nostanding.mp3")], ), ManualAnnouncementEntry( shortName: "Face Covering", informationText: "Please wear a face covering!", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/facecovering.mp3")], ), ManualAnnouncementEntry( shortName: "Seats Upstairs", informationText: "Seats are available upstairs", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/seatsupstairs.mp3")], ), ManualAnnouncementEntry( shortName: "Bus Terminates Here", informationText: "Bus terminates here. Please take your belongings with you", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/busterminateshere.mp3")], ), ManualAnnouncementEntry( shortName: "Bus On Diversion", informationText: "Bus on diversion. Please listen for further announcements", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/busondiversion.mp3")], ), ManualAnnouncementEntry( shortName: "Destination Change", informationText: "Destination Changed - please listen for further instructions", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/destinationchange.mp3")], ), ManualAnnouncementEntry( shortName: "Wheelchair Space", informationText: "Wheelchair space requested", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/wheelchairspace1.mp3")], ), ManualAnnouncementEntry( shortName: "Move Down The Bus", informationText: "Please move down the bus", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/movedownthebus.mp3")], ), ManualAnnouncementEntry( shortName: "Next Stop Closed", informationText: "The next bus stop is closed", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/nextstopclosed.wav")], ), ManualAnnouncementEntry( shortName: "CCTV In Operation", informationText: "CCTV is in operation on this bus", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/cctvoperation.mp3")], ), ManualAnnouncementEntry( shortName: "Safe Door Opening", informationText: "Driver will open the doors when it is safe to do so", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/safedooropening.mp3")], ), ManualAnnouncementEntry( shortName: "Buggy Safety", informationText: "For your child's safety, please remain with your buggy", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/buggysafety.mp3")], ), ManualAnnouncementEntry( shortName: "Wheelchair Space 2", informationText: "Wheelchair priority space required", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/wheelchairspace2.mp3")], ), ManualAnnouncementEntry( shortName: "Service Regulation", informationText: "Regulating service - please listen for further information", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/serviceregulation.mp3")], ), ManualAnnouncementEntry( shortName: "Bus Ready To Depart", informationText: "This bus is ready to depart", audioSources: [AudioWrapperAssetSource("audio/manual_announcements/readytodepart.mp3")], ), ]; } class AnnouncementQueueEntry { final String displayText; final List audioSources; AnnouncementQueueEntry({required this.displayText, required this.audioSources}); } class ManualAnnouncementEntry extends AnnouncementQueueEntry { final String shortName; ManualAnnouncementEntry({required this.shortName, required String informationText, required List audioSources}) : super(displayText: informationText, audioSources: audioSources); }