part of 'runtime_audio_manager.dart'; extension _RuntimeAudioManagerCache on RuntimeAudioManager { void _releaseCachedAudio() { _loadLimiter.clearPending(); for (final path in _audios.keys.toList(growable: false)) { _removeAudioRecord(path); } _channels.clear(); final players = _players.toList(growable: false); _players.clear(); final pooledPlayers = _sfxPool.toList(growable: false); _sfxPool.clear(); for (final player in [...players, ...pooledPlayers]) { player.dispose(); } } RuntimeAudioPlayer _takeSfxPlayer() { if (_sfxPool.isNotEmpty) { return _sfxPool.removeLast(); } return _playerFactory(); } Future _releaseSfxPlayer(RuntimeAudioPlayer player) async { if (_disposed || _sfxPool.length >= _maxSfxPoolSize) { await player.dispose(); return; } _sfxPool.add(player); } void _touch(_AudioResourceRecord record) { record.lastUsed = ++_accessCounter; } void _enforceAudioBudget() { while (_isOverBudget()) { final victim = _leastRecentlyUsedAudio(); if (victim == null || !_removeAudioRecord(victim)) { return; } } } bool _isOverBudget() { final maxBytes = _maxCacheBytes; final maxEntries = _maxCacheEntries; return (maxBytes != null && _cacheBytes > maxBytes) || (maxEntries != null && _readyAudioCount > maxEntries); } int get _readyAudioCount => _audios.values .where((record) => record.state == GameResourceState.ready) .length; String? _leastRecentlyUsedAudio() { String? victimPath; _AudioResourceRecord? victim; for (final entry in _audios.entries) { final record = entry.value; if (record.state != GameResourceState.ready) { continue; } if (victim == null || record.lastUsed < victim.lastUsed) { victim = record; victimPath = entry.key; } } return victimPath; } bool _removeAudioRecord(String path) { final record = _audios.remove(path); if (record == null) { return false; } _cacheBytes -= record.bytes?.length ?? 0; if (_cacheBytes < 0) { _cacheBytes = 0; } record ..state = GameResourceState.disposed ..bytes = null ..inflight = null; return true; } }