Matthias Nott
2026-03-24 d17b6376e8137447c244693853fd05b57aaf368f
fix: audio queue debug logging, 200ms playback state delay
2 files modified
changed files
lib/screens/chat_screen.dart patch | view | blame | history
lib/services/audio_service.dart patch | view | blame | history
lib/screens/chat_screen.dart
....@@ -86,12 +86,18 @@
8686 // Listen for playback state changes to reset play button UI
8787 // Use a brief delay to avoid race between queue transitions
8888 AudioService.onPlaybackStateChanged = () {
89
- if (mounted && !AudioService.isPlaying) {
90
- Future.delayed(const Duration(milliseconds: 100), () {
91
- if (mounted && !AudioService.isPlaying) {
92
- setState(() => _playingMessageId = null);
93
- }
94
- });
89
+ if (mounted) {
90
+ if (AudioService.isPlaying) {
91
+ // Something started playing — keep the indicator as-is
92
+ } else {
93
+ // Playback stopped — clear indicator only if queue is truly empty.
94
+ // Use a short delay since the queue transition has a brief gap.
95
+ Future.delayed(const Duration(milliseconds: 200), () {
96
+ if (mounted && !AudioService.isPlaying) {
97
+ setState(() => _playingMessageId = null);
98
+ }
99
+ });
100
+ }
95101 }
96102 };
97103
....@@ -519,12 +525,7 @@
519525 _scrollToBottom();
520526
521527 if (audioData != null && !AudioService.isBackgrounded && !_isCatchingUp && !_isRecording) {
522
- // Only set playing ID if nothing is currently playing (first chunk).
523
- // Subsequent chunks just queue audio without touching the play indicator,
524
- // preventing the completion callback race from clearing it prematurely.
525
- if (_playingMessageId == null) {
526
- setState(() => _playingMessageId = storedMessage.id);
527
- }
528
+ setState(() => _playingMessageId = storedMessage.id);
528529 AudioService.queueBase64(audioData);
529530 }
530531 }
lib/services/audio_service.dart
....@@ -167,13 +167,20 @@
167167 if (path == null) return;
168168
169169 if (_isPlaying) {
170
- // Already playing — just add to queue, it will play when current finishes
170
+ // Already playing — add to queue, plays when current finishes
171171 _queue.add(path);
172
+ debugPrint('AudioService: queued (queue size: ${_queue.length})');
172173 } else {
173174 // Nothing playing — start immediately
174
- await _player.play(DeviceFileSource(path));
175
- _isPlaying = true;
176
- onPlaybackStateChanged?.call();
175
+ try {
176
+ await _player.play(DeviceFileSource(path));
177
+ _isPlaying = true;
178
+ onPlaybackStateChanged?.call();
179
+ debugPrint('AudioService: playing immediately');
180
+ } catch (e) {
181
+ debugPrint('AudioService: play failed: $e');
182
+ _onTrackComplete();
183
+ }
177184 }
178185 }
179186