[video_player_videohole] Migrating from Platform Channels to Dart FFI - #1073
[video_player_videohole] Migrating from Platform Channels to Dart FFI#1073gin7773 wants to merge 37 commits into
Conversation
…tore the return type of restore.
- Add nlohmann/json single-header library to tizen/third_party/ - Replace handwritten JSON parser with nlohmann/json in ParseJsonMap() - Simplify ParseCreateMessage() to use json library directly - Add EncodableValueFromJson() helper for JSON to EncodableValue conversion This change improves JSON parsing reliability by supporting: - Escape characters in strings - Nested objects and arrays - Unicode characters - Proper error handling with parse_error exceptions Co-Authored-By: Cline SR
- Add UnregisterAllPlayerEventPorts() function in video_player.cc - Add ffi_unregister_all_player_event_ports() FFI wrapper - Add Dart bindings in ffi_messages.g.dart - Call unregisterAllPlayerEventPorts() in init() to clean up ports on hot restart This fix prevents Dart port leaks when the Dart VM is restarted (e.g., hot restart during development) while the native process continues. Co-Authored-By: Cline SR
- Fix FFI event port symbol name mismatch (ffi_register_dart_port) - Call Prepare() after RestorePlayer for two-phase initialization - Return true from Play() when already playing (idempotent) - Remove duplicate play() call in restored event handler Co-Authored-By: Cline SR
- Move all FFI function implementations from video_player_tizen_plugin.cc to ffi_messages.cc - Add ffi_prepare() function that was missing - Use dependency injection pattern (ffi_set_plugin_registrar) for clean boundaries - Keep video_player_tizen_plugin.cc minimal (plugin registration only) Co-Authored-By: Cline SR
> > 1. Fix potential deadlock in PostEventToDart > - Copy port number under lock, then release lock BEFORE calling Dart_PostCObject_DL > - Use explicit scope block to ensure lock is released immediately > - Prevents deadlock if Dart_PostCObject_DL blocks or callbacks into native code > > 2. Remove dead code (player_index variable) > - player_index in video_player.cc is no longer used > - ID generation moved to media_player.cc (player_id_counter) > > Co-Authored-By: Cline SR
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 97da2d750e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Fix the following issues from PR flutter-tizen#1073 reviews: 1. Error event handling missing - Add 'error' event branch in _ensureEventPortRegistered() - Call controller.addError(PlatformException(...)) for error events 2. Seek failure return value not propagated - ffi_seek_to() now returns player->SeekTo(...) ? 0 : -1 3. Plugin lifecycle management missing - Add VideoPlayerTizenPlugin class inheriting flutter::Plugin - Call ffi_dispose_all_players() in destructor - Add ffi_dispose_all_players() function to clean up players and unregister port 4. Dart API DL initialization check missing - Only set _apiDlInitialized if native initialization returns 0 - Throw exception on failure 5. Event port rebinding issue - Change _eventPort from static to instance variable - Each VideoPlayerTizen instance has its own port Co-Authored-By: Cline SR
| static int64_t g_legacy_dart_port = -1; | ||
| static std::mutex g_legacy_dart_port_mutex; | ||
|
|
||
| void ffi_register_event_port(int64_t port) { | ||
| std::lock_guard<std::mutex> lock(g_legacy_dart_port_mutex); | ||
| g_legacy_dart_port = port; | ||
| } | ||
|
|
||
| void ffi_unregister_event_port() { | ||
| std::lock_guard<std::mutex> lock(g_legacy_dart_port_mutex); | ||
| g_legacy_dart_port = -1; | ||
| } |
There was a problem hiding this comment.
Where are these used? They don't look to be in actual use, and
g_legacy_dart_port also looks to be invalid code.
There was a problem hiding this comment.
It has been deleted.
| @@ -0,0 +1,745 @@ | |||
| // Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved. | |||
| return true; | ||
| } | ||
|
|
||
| bool MediaPlayer::StopAndDestroy() { |
There was a problem hiding this comment.
StopAndDestroy() early-returns when player_stop (line 711) or player_unprepare (line 718) fails. On the Dispose/destructor path that failure now leaks the native player handle — the old destructor unconditionally reached player_destroy. For teardown, please follow the repo's "LOG_ERROR + continue" convention so player_destroy (and player_ = nullptr) is always reached, instead of aborting mid-teardown.
| return event_dispatch_state_->disposed; | ||
| } | ||
| return true; // If no event_dispatch_state_, consider as disposed | ||
| } |
There was a problem hiding this comment.
Does isDisposed() work as intended?
After ~VideoPlayer() is called std::shared_ptr event_dispatch_state_; is valid?
and OnPrepared (line 918) is the only callback missing the guard — please align it.
| // Use FFI for initialization (synchronous call) | ||
| final int result = _ffiApi.initialize(); | ||
| if (result != 0) { | ||
| throw Exception('FFI initialize failed with code: $result'); |
There was a problem hiding this comment.
Throwing plain Exception on FFI failure changes the app-visible error contract — the previous pigeon implementation (and sibling plugins) throw PlatformException, and the event stream already delivers PlatformException after the earlier review fix. Please unify the method paths on PlatformException (code + message) so existing on PlatformException handlers keep working.
| return _api.seekTo( | ||
| PositionMessage(playerId: playerId, position: position.inMilliseconds), | ||
| ); | ||
| Future<void> seekTo(int playerId, Duration position) async { |
There was a problem hiding this comment.
It seems there are some changes from the existing behavior.
seekTo()'s Future now completes when the seek starts (empty callback in ffi_seek_to), not when it finishes as before — so post-await position reads can be stale and rapid consecutive seeks can fail; please complete it via a seekCompleted event through the existing port.
Please check this
| // Phase 2: Register global Dart port (only needs to be done once) | ||
| // Note: registerDartPort is now a no-op since we use global port | ||
| // The port is already registered in _ensureEventPortRegistered() |
There was a problem hiding this comment.
It has been deleted.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd3e299820
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Main changes:
Threading note
After migrating from Platform Channels to Dart FFI, some native calls are invoked synchronously from the Flutter UI thread rather than through the previous platform-channel handler path. The ecore_wl2 display path is marked with a TODO because those APIs are not thread-safe and will be revisited during the planned ecore-to-GLib migration.