Player constructor

Player()

Implementation

Player() {
  _pp.value = _player;
  _receivePort.listen((message) async {
    final type = message[0] as int;
    final rep = calloc<_CallbackReply>();
    switch (type) {
      case 0:
        {
          // event
          final error = message[1] as int;
          final category = message[2] as String;
          final detail = message[3] as String;
          final ev = MediaEvent(error, category, detail);
          for (final cb in _eventCb) {
            cb(ev);
          }
        }
      case 1:
        {
          // state
          final oldValue = message[1] as int;
          final newValue = message[2] as int;
          for (final cb in _stateCb) {
            cb(PlaybackState.from(oldValue), PlaybackState.from(newValue));
          }
          Libfvp.replyType(nativeHandle, type, nullptr);
        }
      case 2:
        {
          // media status
          final oldValue = message[1] as int;
          final newValue = message[2] as int;
          bool ret = true;
          for (var cb in _statusCb) {
            ret = cb(MediaStatus(oldValue), MediaStatus(newValue)) && ret;
          }
          rep.ref.mediaStatus.ret = ret;
          Libfvp.replyType(nativeHandle, type, rep.cast());
        }
      case 3:
        {
          // prepared
          final pos = message[1] as int;
          _live = message[2] as bool;
          if (!_prepared.isCompleted) {
            _prepared.complete(pos);
          }
          rep.ref.prepared.ret = true;
          rep.ref.prepared.boost = true;
          /*
          // callback can be late if prepare from pos > 0
          if (_videoSize.isCompleted)
            _videoSize = Completer<ui.Size?>();
          if (!_videoSize.isCompleted) {
            if (pos < 0) {
              _videoSize.complete(null);
            } else {
              _setVideoSize();
            }
          }*/
          if (_prepareCb != null) {
            rep.ref.prepared.ret = await _prepareCb!();
            _prepareCb = null;
          }
          Libfvp.replyType(nativeHandle, type, rep.cast());
        }
      case 6:
        {
          // seek
          final pos = message[1] as int;
          if (!(_seeked?.isCompleted ?? true)) {
            _seeked?.complete(pos);
          }
          _seeked = null;
        }
      case 7:
        {
          final data = message[1] as Uint8List; //null?
          if (!(_snapshot?.isCompleted ?? true)) {
            _snapshot?.complete(data.isEmpty ? null : data);
          }
          _snapshot = null;
        }
    }
    calloc.free(rep);
  });
  Libfvp.registerPort(nativeHandle, NativeApi.postCObject.cast(),
      _receivePort.sendPort.nativePort);

  onStateChanged((oldValue, newValue) {
    _state = newValue;
  });
  onMediaStatus((oldValue, newValue) {
    if (!oldValue.test(MediaStatus.loaded) &&
        newValue.test(MediaStatus.loaded)) {
      _setVideoSize();
    }
    if (!oldValue.test(MediaStatus.loading) &&
        newValue.test(MediaStatus.loading)) {
      if (_videoSize.isCompleted) {
        // updateTexture() may be awaiting and won't wake up if reset to a new object here
        _videoSize = Completer<ui.Size?>();
      }
    }
    if (oldValue.test(MediaStatus.loading) &&
        newValue.test(MediaStatus.invalid | MediaStatus.stalled)) {
      _videoSize.complete(null);
    }
    if (oldValue.test(MediaStatus.loaded) &&
        !newValue.test(MediaStatus.loaded)) {
// invalid mediaInfo when loaded(small probe size, bad format etc.), then failed to decode
      if (!_videoSize.isCompleted) {
        _videoSize.complete(null);
      }
    }
    return true;
  });
  onEvent((e) {
    if (_videoSize.isCompleted) {
      return;
    }
    if (e.category == 'decoder.video') {
      _setVideoSize();
    }
  });
}