125 lines
3.4 KiB
Dart
125 lines
3.4 KiB
Dart
part of 'runtime_audio_manager.dart';
|
|
|
|
extension _RuntimeAudioManagerLoading on RuntimeAudioManager {
|
|
Future<Uint8List?> _loadAudio(
|
|
String? keyOrPath, {
|
|
required bool failOnError,
|
|
}) {
|
|
if (keyOrPath == null || keyOrPath.isEmpty) {
|
|
return Future.value(null);
|
|
}
|
|
|
|
final requestToken = _asyncGate.token;
|
|
final requestGeneration = requestToken.generation;
|
|
final path = _tryResolve(keyOrPath);
|
|
if (path == null) {
|
|
return Future.value(null);
|
|
}
|
|
|
|
final existing = _audios[path];
|
|
if (existing != null) {
|
|
final bytes = existing.bytes;
|
|
if (existing.generation == requestGeneration &&
|
|
existing.state == GameResourceState.ready &&
|
|
bytes != null) {
|
|
_touch(existing);
|
|
return Future.value(bytes);
|
|
}
|
|
final inflight = existing.inflight;
|
|
if (existing.generation == requestGeneration && inflight != null) {
|
|
return failOnError
|
|
? _throwIfNull(inflight, keyOrPath)
|
|
: inflight.catchError((_) => null);
|
|
}
|
|
}
|
|
|
|
final record = _AudioResourceRecord(generation: requestGeneration)
|
|
..state = GameResourceState.loading;
|
|
_audios[path] = record;
|
|
|
|
final future = _readAudio(path, record, requestToken);
|
|
record.inflight = future;
|
|
return failOnError ? _throwIfNull(future, keyOrPath) : future;
|
|
}
|
|
|
|
Future<Uint8List?> _throwIfNull(
|
|
Future<Uint8List?> future,
|
|
String keyOrPath,
|
|
) async {
|
|
final bytes = await future;
|
|
if (bytes == null) {
|
|
throw ResourceLoadException('Required audio resource failed: $keyOrPath');
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
Future<Uint8List?> _readAudio(
|
|
String path,
|
|
_AudioResourceRecord record,
|
|
RuntimeAsyncToken requestToken,
|
|
) async {
|
|
try {
|
|
final activePackage = _package;
|
|
if (activePackage == null) {
|
|
throw StateError('RuntimeAudioManager has no active package');
|
|
}
|
|
|
|
final ownedBytes = await _loadLimiter.run(() async {
|
|
final data = await activePackage.readBytes(path);
|
|
final bytes = data.buffer.asUint8List(
|
|
data.offsetInBytes,
|
|
data.lengthInBytes,
|
|
);
|
|
return Uint8List.fromList(bytes);
|
|
});
|
|
record.inflight = null;
|
|
|
|
if (_disposed ||
|
|
!_asyncGate.accepts(requestToken) ||
|
|
_audios[path] != record) {
|
|
record.state = GameResourceState.disposed;
|
|
return null;
|
|
}
|
|
|
|
record
|
|
..bytes = ownedBytes
|
|
..state = GameResourceState.ready
|
|
..lastError = null;
|
|
_cacheBytes += ownedBytes.length;
|
|
_touch(record);
|
|
_enforceAudioBudget();
|
|
return ownedBytes;
|
|
} catch (error) {
|
|
record.inflight = null;
|
|
if (_disposed ||
|
|
!_asyncGate.accepts(requestToken) ||
|
|
_audios[path] != record) {
|
|
record.state = GameResourceState.disposed;
|
|
return null;
|
|
}
|
|
record
|
|
..state = GameResourceState.failed
|
|
..lastError = error;
|
|
_diagnostics?.record(
|
|
type: RuntimeDiagnosticType.resourceLoadError,
|
|
message: 'Audio resource failed to load',
|
|
error: error,
|
|
context: {'path': path, 'generation': requestToken.generation},
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
String? _tryResolve(String keyOrPath) {
|
|
try {
|
|
final activePackage = _package;
|
|
if (activePackage == null) {
|
|
return null;
|
|
}
|
|
return activePackage.resolveResourcePath(keyOrPath);
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|