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);
if (_eventCb.hasListener) {
_eventCb.add(ev);
}
}
case 1:
{
// state
final oldValue = message[1] as int;
final newValue = message[2] as int;
if (_stateCb.hasListener) {
_stateCb.add((
oldValue: PlaybackState.from(oldValue),
newValue: 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;
if (_statusCb.hasListener) {
_statusCb.add((
oldValue: MediaStatus(oldValue),
newValue: MediaStatus(newValue),
));
}
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;
}
case 8:
{
final start = message[1] as double;
final end = message[2] as double;
final texts = (message[3] as List).cast<String>();
_subtitleCb?.call(start, end, texts);
}
}
calloc.free(rep);
});
Libfvp.registerPort(
nativeHandle,
NativeApi.postCObject.cast(),
_receivePort.sendPort.nativePort,
);
_stateCb.stream.listen((event) {
_state = event.newValue;
});
Libfvp.registerType(nativeHandle, 1, false);
_statusCb.stream.listen((event) {
final oldValue = event.oldValue;
final newValue = event.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);
}
}
});
Libfvp.registerType(nativeHandle, 2, false);
_eventCb.stream.listen((e) {
if (_videoSize.isCompleted) {
return;
}
if (e.category == 'decoder.video') {
_setVideoSize();
}
});
Libfvp.registerType(nativeHandle, 0, false);
}