play static method

Stream<void> play(
  1. String asset, {
  2. bool loop = false,
})

Plays the provided asset.

If the returned Stream is canceled, then the playback stops.

Implementation

static Stream<void> play(String asset, {bool loop = false}) {
  Log.debug('play($asset, loop: $loop)', 'WebUtils');

  StreamController? controller;
  StreamSubscription? onEnded;
  web.AudioBufferSourceNode? node;

  controller = StreamController(
    onListen: () async {
      _context ??= web.AudioContext();
      if (_context?.state == 'suspended') {
        Log.debug(
          'play($asset, loop: $loop) -> _context?.state == `suspended`, resuming',
          'WebUtils',
        );

        await (_context?.resume())?.toDart;
      }

      if (controller?.hasListener == false) {
        return;
      }

      if (_context == null) {
        throw Exception('AudioContext is `null`, cannot `play($asset)`');
      }

      final web.AudioBufferSourceNode source = _context!.createBufferSource();

      final Response bytes = await (await PlatformUtils.dio).get(
        'assets/assets/$asset',
        options: Options(responseType: ResponseType.bytes),
      );

      if (controller?.hasListener == false) {
        return;
      }

      final JSPromise<web.AudioBuffer> audioBuffer = _context!
          .decodeAudioData((bytes.data as Uint8List).buffer.toJS);

      node = source;
      source.buffer = await audioBuffer.toDart;

      if (controller?.hasListener == false) {
        return;
      }

      source.loop = loop;
      source.connect(_context!.destination);
      source.start();
      onEnded = source.onEnded.listen((_) {
        controller?.close();
      });
    },
    onCancel: () {
      onEnded?.cancel();
      node?.stop();
      controller?.close();
    },
  );

  return controller.stream;
}