fix(android): apply dv conversion mode during init
This commit is contained in:
@@ -195,7 +195,15 @@ class PlayerAndroid extends PlayerBase {
|
||||
break;
|
||||
case 'dv-conversion-mode':
|
||||
_dvConversionMode = value;
|
||||
if (initialized) await invoke('setDvConversionMode', {'mode': value});
|
||||
final initFuture = _initFuture;
|
||||
if (initialized) {
|
||||
await invoke('setDvConversionMode', {'mode': value});
|
||||
} else if (initFuture != null) {
|
||||
await initFuture;
|
||||
if (!disposed && initialized && _dvConversionMode == value) {
|
||||
await invoke('setDvConversionMode', {'mode': value});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'sub-visibility':
|
||||
if (value == 'no') {
|
||||
|
||||
@@ -566,13 +566,6 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
player = currentPlayer;
|
||||
_playerBackendLabel = currentPlayer.playerType;
|
||||
|
||||
// Kick off audio-focus negotiation in parallel with MPV config + prefetch.
|
||||
// On Android this is a round-trip to AudioManager (~90ms cold).
|
||||
if (Platform.isAndroid && !widget.isLive) {
|
||||
_audioFocusFuture = currentPlayer.requestAudioFocus();
|
||||
_audioFocusFuture!.ignore();
|
||||
}
|
||||
|
||||
// Kick off getPlaybackData() in parallel with the rest of MPV setup.
|
||||
// The network/DB work has no dependency on the player — it just needs
|
||||
// the context (providers), which is still safe to touch here because
|
||||
@@ -670,6 +663,12 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
}
|
||||
}
|
||||
}
|
||||
// requestAudioFocus initializes Android players, so start it only after
|
||||
// init-time ExoPlayer options above have been cached.
|
||||
if (Platform.isAndroid && !widget.isLive) {
|
||||
_audioFocusFuture = currentPlayer.requestAudioFocus();
|
||||
_audioFocusFuture!.ignore();
|
||||
}
|
||||
await currentPlayer.setProperty('msg-level', debugLoggingEnabled ? 'all=debug' : 'all=error');
|
||||
await currentPlayer.setLogLevel(debugLoggingEnabled ? 'v' : 'warn');
|
||||
await currentPlayer.setProperty('hwdec', _getHwdecValue(enableHardwareDecoding));
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:plezy/mpv/mpv.dart';
|
||||
@@ -32,6 +34,53 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test('ExoPlayer applies DV conversion mode changed during in-flight initialization', () async {
|
||||
final initialize = Completer<bool>();
|
||||
final calls = <MethodCall>[];
|
||||
|
||||
await _withMockChannels(
|
||||
methodChannelName: 'com.plezy/exo_player',
|
||||
eventChannelName: 'com.plezy/exo_player/events',
|
||||
methodHandler: (call) {
|
||||
calls.add(call);
|
||||
switch (call.method) {
|
||||
case 'initialize':
|
||||
return initialize.future;
|
||||
case 'requestAudioFocus':
|
||||
return Future.value(true);
|
||||
default:
|
||||
return Future.value(null);
|
||||
}
|
||||
},
|
||||
testBody: () async {
|
||||
final player = PlayerAndroid();
|
||||
try {
|
||||
final focusFuture = player.requestAudioFocus();
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
final modeFuture = player.setProperty('dv-conversion-mode', 'hevc_strip');
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
|
||||
final initCall = calls.singleWhere((call) => call.method == 'initialize');
|
||||
final initArgs = Map<Object?, Object?>.from(initCall.arguments as Map);
|
||||
expect(initArgs['dvConversionMode'], 'auto');
|
||||
expect(calls.where((call) => call.method == 'setDvConversionMode'), isEmpty);
|
||||
|
||||
initialize.complete(true);
|
||||
await modeFuture;
|
||||
await focusFuture;
|
||||
|
||||
final dvCall = calls.singleWhere((call) => call.method == 'setDvConversionMode');
|
||||
final dvArgs = Map<Object?, Object?>.from(dvCall.arguments as Map);
|
||||
expect(dvArgs['mode'], 'hevc_strip');
|
||||
} finally {
|
||||
if (!initialize.isCompleted) initialize.complete(true);
|
||||
await player.dispose();
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('MPV clears stale Dart track state before opening new media', () async {
|
||||
await _withMockChannels(
|
||||
methodChannelName: 'com.plezy/mpv_player',
|
||||
@@ -61,27 +110,32 @@ void main() {
|
||||
Future<void> _withMockChannels({
|
||||
required String methodChannelName,
|
||||
required String eventChannelName,
|
||||
Future<Object?> Function(MethodCall call)? methodHandler,
|
||||
required Future<void> Function() testBody,
|
||||
}) async {
|
||||
final messenger = TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger;
|
||||
final methodChannel = MethodChannel(methodChannelName);
|
||||
final eventChannel = MethodChannel(eventChannelName);
|
||||
|
||||
messenger.setMockMethodCallHandler(methodChannel, (call) async {
|
||||
switch (call.method) {
|
||||
case 'initialize':
|
||||
return true;
|
||||
case 'observeProperty':
|
||||
case 'setVisible':
|
||||
case 'setProperty':
|
||||
case 'command':
|
||||
case 'open':
|
||||
case 'dispose':
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
messenger.setMockMethodCallHandler(
|
||||
methodChannel,
|
||||
methodHandler ??
|
||||
(call) async {
|
||||
switch (call.method) {
|
||||
case 'initialize':
|
||||
return true;
|
||||
case 'observeProperty':
|
||||
case 'setVisible':
|
||||
case 'setProperty':
|
||||
case 'command':
|
||||
case 'open':
|
||||
case 'dispose':
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
);
|
||||
messenger.setMockMethodCallHandler(eventChannel, (call) async => null);
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user