diff --git a/ios/Podfile.lock b/ios/Podfile.lock index b9ba8a7..2222213 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4,19 +4,19 @@ PODS: - device_info_plus (0.0.1): - Flutter - Flutter (1.0.0) - - flutter_webrtc (0.14.0): + - flutter_webrtc (1.1.0): - Flutter - - WebRTC-SDK (= 125.6422.07) - - livekit_client (2.4.9): + - WebRTC-SDK (= 137.7151.03) + - livekit_client (2.5.0): - Flutter - flutter_webrtc - - WebRTC-SDK (= 125.6422.07) + - WebRTC-SDK (= 137.7151.03) - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - url_launcher_ios (0.0.1): - Flutter - - WebRTC-SDK (125.6422.07) + - WebRTC-SDK (137.7151.03) DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) @@ -51,11 +51,11 @@ SPEC CHECKSUMS: connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 - flutter_webrtc: fd0d3bdef8766a0736dbbe2e5b7e85f1f3c52117 - livekit_client: 3f79d79233a5bd13d5b541732624ef959d7c538e + flutter_webrtc: b0b2e04411747142962164a1cfa43a1af9a0afac + livekit_client: f810c81bbbc229a84f60b09e66603ac4e93f7599 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 url_launcher_ios: 694010445543906933d732453a59da0a173ae33d - WebRTC-SDK: dff00a3892bc570b6014e046297782084071657e + WebRTC-SDK: 69d4e56b0b4b27d788e87bab9b9a1326ed05b1e3 PODFILE CHECKSUM: a57f30d18f102dd3ce366b1d62a55ecbef2158e5 diff --git a/lib/controllers/app_ctrl.dart b/lib/controllers/app_ctrl.dart index 880b410..e76f7f7 100644 --- a/lib/controllers/app_ctrl.dart +++ b/lib/controllers/app_ctrl.dart @@ -24,6 +24,7 @@ class AppCtrl extends ChangeNotifier { AppScreenState appScreenState = AppScreenState.welcome; ConnectionState connectionState = ConnectionState.disconnected; AgentScreenState agentScreenState = AgentScreenState.visualizer; + bool isAgentListening = false; //Test bool isUserCameEnabled = false; @@ -42,6 +43,10 @@ class AppCtrl extends ChangeNotifier { // Timer for checking agent connection Timer? _agentConnectionTimer; + // Event listeners cleanup functions + sdk.CancelListenFunc? _preConnectAudioStartedListener; + sdk.CancelListenFunc? _preConnectAudioStoppedListener; + AppCtrl() { final format = DateFormat('HH:mm:ss'); // configure logs for debugging @@ -57,12 +62,16 @@ class AppCtrl extends ChangeNotifier { notifyListeners(); } }); + + // Listen for pre-connect audio buffer events + _setupPreConnectAudioListeners(); } @override void dispose() { messageCtrl.dispose(); _cancelAgentTimer(); + _cleanupPreConnectAudioListeners(); super.dispose(); } @@ -101,36 +110,58 @@ class AppCtrl extends ChangeNotifier { notifyListeners(); } + void _setupPreConnectAudioListeners() { + _preConnectAudioStartedListener = room.events.on((event) { + _logger.info('Pre-connect audio buffer started: ${event.sampleRate}Hz, timeout: ${event.timeout}'); + isAgentListening = true; + notifyListeners(); + }); + + _preConnectAudioStoppedListener = room.events.on((event) { + _logger.info('Pre-connect audio buffer stopped: ${event.bufferedSize} bytes, sent: ${event.isBufferSent}'); + isAgentListening = false; + notifyListeners(); + }); + } + + void _cleanupPreConnectAudioListeners() { + _preConnectAudioStartedListener?.call(); + _preConnectAudioStartedListener = null; + _preConnectAudioStoppedListener?.call(); + _preConnectAudioStoppedListener = null; + } + void connect() async { _logger.info("Connect...."); connectionState = ConnectionState.connecting; notifyListeners(); try { - // Generate random room and participant names - // In a real app, you'd likely use meaningful names - final roomName = 'room-${(1000 + DateTime.now().millisecondsSinceEpoch % 9000)}'; - final participantName = 'user-${(1000 + DateTime.now().millisecondsSinceEpoch % 9000)}'; - - // Get connection details from token service - final connectionDetails = await tokenService.fetchConnectionDetails( - roomName: roomName, - participantName: participantName, - ); + _logger.info("Starting pre-connect audio..."); - _logger.info("Fetched Connection Details: $connectionDetails, connecting to room..."); + await room.withPreConnectAudio(() async { + _logger.info("Pre-connect audio started..."); - await room.connect( - connectionDetails.serverUrl, - connectionDetails.participantToken, - ); + // Generate random room and participant names + // In a real app, you'd likely use meaningful names + final roomName = 'room-${(1000 + DateTime.now().millisecondsSinceEpoch % 9000)}'; + final participantName = 'user-${(1000 + DateTime.now().millisecondsSinceEpoch % 9000)}'; - _logger.info("Connected to room"); + // Get connection details from token service + final connectionDetails = await tokenService.fetchConnectionDetails( + roomName: roomName, + participantName: participantName, + ); - await room.localParticipant?.setMicrophoneEnabled(true); + _logger.info("Fetched Connection Details: $connectionDetails, connecting to room..."); - _logger.info("Microphone enabled"); + await room.connect( + connectionDetails.serverUrl, + connectionDetails.participantToken, + ); + _logger.info("Connected to room"); + }); connectionState = ConnectionState.connected; appScreenState = AppScreenState.agent; @@ -143,6 +174,7 @@ class AppCtrl extends ChangeNotifier { connectionState = ConnectionState.disconnected; appScreenState = AppScreenState.welcome; + isAgentListening = false; notifyListeners(); } } @@ -155,6 +187,7 @@ class AppCtrl extends ChangeNotifier { connectionState = ConnectionState.disconnected; appScreenState = AppScreenState.welcome; agentScreenState = AgentScreenState.visualizer; + isAgentListening = false; notifyListeners(); } diff --git a/lib/screens/welcome_screen.dart b/lib/screens/welcome_screen.dart index 2fc283a..130a7fb 100644 --- a/lib/screens/welcome_screen.dart +++ b/lib/screens/welcome_screen.dart @@ -49,6 +49,34 @@ class WelcomeScreen extends StatelessWidget { ], ), ), + // Agent listening indicator + Consumer( + builder: (ctx, appCtrl, child) => AnimatedOpacity( + opacity: appCtrl.isAgentListening ? 1.0 : 0.0, + duration: const Duration(milliseconds: 300), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.mic, + color: Colors.green, + size: 18, + ), + const SizedBox(width: 8), + const Text( + 'Agent is listening', + style: TextStyle( + color: Colors.green, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ), + ), Builder( builder: (ctx) { final isProgressing = [ diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 5d8e94b..1779669 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -3,20 +3,20 @@ PODS: - FlutterMacOS - device_info_plus (0.0.1): - FlutterMacOS - - flutter_webrtc (0.14.0): + - flutter_webrtc (1.1.0): - FlutterMacOS - - WebRTC-SDK (= 125.6422.07) + - WebRTC-SDK (= 137.7151.03) - FlutterMacOS (1.0.0) - - livekit_client (2.4.9): + - livekit_client (2.5.0): - flutter_webrtc - FlutterMacOS - - WebRTC-SDK (= 125.6422.07) + - WebRTC-SDK (= 137.7151.03) - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS - - WebRTC-SDK (125.6422.07) + - WebRTC-SDK (137.7151.03) DEPENDENCIES: - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) @@ -50,12 +50,12 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 - flutter_webrtc: a7eeb54859e672228c28f4b48b1fb61561976ea3 + flutter_webrtc: 1ce7fe9a42f085286378355a575e682edd7f114d FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 - livekit_client: c9d9f41996f5cf22b9ba0e8483e6af4ca5094059 + livekit_client: 5a5c0f1081978542bbf9a986c7ac9bffcdb73906 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 - WebRTC-SDK: dff00a3892bc570b6014e046297782084071657e + WebRTC-SDK: 69d4e56b0b4b27d788e87bab9b9a1326ed05b1e3 PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index adbffad..4e6a1a6 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -66,7 +66,7 @@ 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* voice_assistant.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = voice_assistant.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* Voice Assistant.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Voice Assistant.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -144,7 +144,7 @@ 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* voice_assistant.app */, + 33CC10ED2044A3C60003C045 /* Voice Assistant.app */, 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; @@ -195,7 +195,6 @@ A456EC03A0B3E32F7C86CADF /* Pods-RunnerTests.release.xcconfig */, 93FFB8C7B6A7F2D36EE98E96 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -249,7 +248,7 @@ ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* voice_assistant.app */; + productReference = 33CC10ED2044A3C60003C045 /* Voice Assistant.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -579,6 +578,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -711,6 +711,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -731,6 +732,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; };