just_audio icon indicating copy to clipboard operation
just_audio copied to clipboard

An Unhandled Exception is thrown when loading LockCachingAudioSource fails.

Open OwlWen opened this issue 11 months ago • 1 comments

Which API doesn't behave as documented, and how does it misbehave? Set audio source to LockCachingAudioSource type, preload to false, get Unhandled Exception after calling player.load method.

Minimal reproduction project The example

try {
    final source = LockCachingAudioSource(Uri.parse(
        "https://no-exist-url.test-host/test.mp3"));
    await _player.setAudioSource(source, preload: false);

    // Calling the load method at other times
    await _player.load();
} catch (e) {
    print("Error loading audio source: $e");
}

To Reproduce (i.e. user steps, not code) Steps to reproduce the behavior:

  1. Set audio source to LockCachingAudioSource type, preload to false.
  2. Call player.load method.

Error messages

[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: SocketException: Failed host lookup: 'no-exist-url.test-host' (OS Error: nodename nor servname provided, or not known, errno = 8)
#0      _NativeSocket.startConnect (dart:io-patch/socket_patch.dart:682:35)
#1      _RawSocket.startConnect (dart:io-patch/socket_patch.dart:1827:26)
#2      RawSocket.startConnect (dart:io-patch/socket_patch.dart:27:23)
#3      RawSecureSocket.startConnect (dart:io/secure_socket.dart:299:22)
#4      SecureSocket.startConnect (dart:io/secure_socket.dart:77:28)
#5      _ConnectionTarget.connect (dart:_http/http_impl.dart:2449:26)
#6      _HttpClient._getConnection.connect (dart:_http/http_impl.dart:2867:12)
#7      _HttpClient._getConnection (dart:_http/http_impl.dart:2872:12)
#8      _HttpClient._openUrl (dart:_http/http_impl.dart:2727:12)
#9      _HttpClient.getUrl (dart:_http/http_impl.dart:2596:48)
#10     _getUrl (package:just_audio/just_audio.dart:3936:32)
#11     LockCachingAudioSource._fetch (package:just_a<…>

Expected behavior An Unhandled Exception is thrown.

Screenshots N/A

Desktop (please complete the following information): Not running on Desktop / Web

Smartphone (please complete the following information):

  • Device: iPhone8
  • OS: iOS16.1

Flutter SDK version

Flutter 3.3.3

Additional context The code that threw the exception: In LockCachingAudioSource.request(), Future error is thrown when fetch fails, but cannot be handled.

// Line: 3120
_response ??=
    _fetch().catchError((dynamic error, StackTrace? stackTrace) async {

    _response = null;

    for (final req in _requests) {
    req.fail(error, stackTrace);
    }

    // Return a Future Error, which cannot be handled by outer.
    return Future<HttpClientResponse>.error(error as Object, stackTrace);
});

Bug Fix Suggestion: I think it's unnecessary to cache the fetch Future object, but rather use an isFetching variable to preserve the state. Since there isn't currently any retry logic, the fetch result is actually ignore. Even if retry logic is added later, call the fetch method directly and does not require the last failed Future object.

bool _isFetching = false;

Future<void> _fetchIgnoreResult() async {
  try {
    await _fetch();
  } catch (error, stackTrace) {
    // Cancel any pending request
    for (final req in _requests) {
      req.fail(error, stackTrace);
    }
  }
  _isFetching = false;
}

if (!_isFetching) {
  _isFetching = true;
  _fetchIgnoreResult();
}

OwlWen avatar Mar 24 '24 06:03 OwlWen