fix(native): harden player teardown and shelf recovery

This commit is contained in:
edde746
2026-07-25 16:16:24 +02:00
parent 4af77f4696
commit f8f366a513
26 changed files with 2895 additions and 302 deletions
+11 -11
View File
@@ -10,6 +10,14 @@ import QuartzCore
import Metal
#endif
struct MpvLifecycleUnavailableError: LocalizedError {
let errorDescription: String?
init(_ description: String) {
errorDescription = description
}
}
protocol MpvPlayerDelegate: AnyObject {
func onPropertyChange(name: String, value: Any?)
func onEvent(name: String, data: [String: Any]?)
@@ -944,11 +952,7 @@ class MpvPlayerCoreBase: NSObject {
pendingRequests.removeAll()
pendingRequestsLock.unlock()
let error = NSError(
domain: "mpv",
code: -1,
userInfo: [NSLocalizedDescriptionKey: "Player disposed"]
)
let error = MpvLifecycleUnavailableError("Player disposed")
for (_, request) in pending {
DispatchQueue.main.async {
switch request {
@@ -977,12 +981,8 @@ class MpvPlayerCoreBase: NSObject {
return pendingRequests.removeValue(forKey: requestId)
}
private func lifecycleUnavailableError() -> NSError {
NSError(
domain: "mpv",
code: -1,
userInfo: [NSLocalizedDescriptionKey: "Player is not initialized or has been disposed"]
)
private func lifecycleUnavailableError() -> MpvLifecycleUnavailableError {
MpvLifecycleUnavailableError("Player is not initialized or has been disposed")
}
private func mpvError(_ status: CInt) -> NSError {
@@ -49,11 +49,15 @@ extension MpvPluginShared {
self?.didSetPauseProperty(value: value)
}
result(nil)
case .failure:
case .failure(let error):
let lifecycleUnavailable = error is MpvLifecycleUnavailableError
result(
FlutterError(
code: "SET_PROPERTY_FAILED",
message: "MPV rejected or cancelled the property write",
code: lifecycleUnavailable ? "NOT_INITIALIZED" : "SET_PROPERTY_FAILED",
message:
lifecycleUnavailable
? "MPV player is not initialized"
: "MPV rejected or cancelled the property write",
details: nil))
}
}
+4
View File
@@ -26,6 +26,10 @@ static constexpr size_t kSetPropertyErrorDescriptionLimit = 160;
inline bool SetPropertyStatusSucceeded(int status) { return status >= 0; }
inline const char* SetPropertyErrorCode(int status) {
return status == MPV_ERROR_UNINITIALIZED ? kSetPropertyNotInitializedCode : kSetPropertyFailedCode;
}
inline std::string SetPropertyErrorDescription(int status) {
const char* description = mpv_error_string(status);
if (!description || description[0] == '\0') {
+16 -3
View File
@@ -81,14 +81,27 @@ void TestSetPropertyResultContract() {
assert(SetPropertyStatusSucceeded(MPV_ERROR_SUCCESS));
assert(SetPropertyStatusSucceeded(1));
constexpr int kFailureStatuses[] = {
assert(!SetPropertyStatusSucceeded(MPV_ERROR_UNINITIALIZED));
assert(std::string(SetPropertyErrorCode(MPV_ERROR_UNINITIALIZED)) == kSetPropertyNotInitializedCode);
constexpr int kRejectedStatuses[] = {
MPV_ERROR_INVALID_PARAMETER,
MPV_ERROR_PROPERTY_ERROR,
-1,
};
for (const int status : kRejectedStatuses) {
assert(!SetPropertyStatusSucceeded(status));
assert(std::string(SetPropertyErrorCode(status)) == kSetPropertyFailedCode);
}
constexpr int kDescribedStatuses[] = {
MPV_ERROR_INVALID_PARAMETER,
MPV_ERROR_PROPERTY_ERROR,
-1,
MPV_ERROR_UNINITIALIZED,
};
for (const int status : kFailureStatuses) {
assert(!SetPropertyStatusSucceeded(status));
for (const int status : kDescribedStatuses) {
const std::string description = SetPropertyErrorDescription(status);
assert(!description.empty());
assert(description.size() <= kSetPropertyErrorDescriptionLimit);