diff --git a/packages/video_player/CHANGELOG.md b/packages/video_player/CHANGELOG.md index af6e235f3..13478ee63 100644 --- a/packages/video_player/CHANGELOG.md +++ b/packages/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.4.9 + +* Fix event channel issue, sending messages from native to Flutter on the platform thread. + ## 2.4.8 * Disable screensaver when player is playing. diff --git a/packages/video_player/README.md b/packages/video_player/README.md index f71d244ea..426a663cc 100644 --- a/packages/video_player/README.md +++ b/packages/video_player/README.md @@ -15,7 +15,7 @@ This package is not an _endorsed_ implementation of `video_player`. Therefore, y ```yaml dependencies: video_player: ^2.4.2 - video_player_tizen: ^2.4.8 + video_player_tizen: ^2.4.9 ``` Then you can import `video_player` in your Dart code: diff --git a/packages/video_player/pubspec.yaml b/packages/video_player/pubspec.yaml index f0042d87e..55dec9357 100644 --- a/packages/video_player/pubspec.yaml +++ b/packages/video_player/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_tizen description: Tizen implementation of the video_player plugin. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/video_player -version: 2.4.8 +version: 2.4.9 environment: sdk: ">=2.18.0 <4.0.0" diff --git a/packages/video_player/tizen/src/video_player.cc b/packages/video_player/tizen/src/video_player.cc index 71a984303..18b855d8e 100644 --- a/packages/video_player/tizen/src/video_player.cc +++ b/packages/video_player/tizen/src/video_player.cc @@ -111,6 +111,13 @@ void VideoPlayer::InitScreenSaverApi() { VideoPlayer::VideoPlayer(flutter::PluginRegistrar *plugin_registrar, flutter::TextureRegistrar *texture_registrar, const std::string &uri, VideoPlayerOptions &options) { + sink_event_pipe_ = ecore_pipe_add( + [](void *data, void *buffer, unsigned int nbyte) -> void { + auto *self = static_cast(data); + self->SendPendingEvents(); + }, + this); + texture_registrar_ = texture_registrar; texture_variant_ = @@ -205,6 +212,45 @@ VideoPlayer::~VideoPlayer() { } } +void VideoPlayer::SendPendingEvents() { + std::lock_guard lock(queue_mutex_); + while (!encodable_event_queue_.empty()) { + if (event_sink_) { + event_sink_->Success(encodable_event_queue_.front()); + } + encodable_event_queue_.pop(); + } + + while (!error_event_queue_.empty()) { + if (event_sink_) { + event_sink_->Error(error_event_queue_.front().first, + error_event_queue_.front().second); + } + error_event_queue_.pop(); + } +} + +void VideoPlayer::PushEvent(const flutter::EncodableValue &encodable_value) { + if (!event_sink_) { + LOG_ERROR("[VideoPlayer] event sink is nullptr."); + return; + } + std::lock_guard lock(queue_mutex_); + encodable_event_queue_.push(encodable_value); + ecore_pipe_write(sink_event_pipe_, nullptr, 0); +} + +void VideoPlayer::SendError(const std::string &error_code, + const std::string &error_message) { + if (!event_sink_) { + LOG_ERROR("[VideoPlayer] event sink is nullptr."); + return; + } + std::lock_guard lock(queue_mutex_); + error_event_queue_.push(std::make_pair(error_code, error_message)); + ecore_pipe_write(sink_event_pipe_, nullptr, 0); +} + void VideoPlayer::Play() { LOG_DEBUG("[VideoPlayer] Player starting."); @@ -306,6 +352,11 @@ void VideoPlayer::Dispose() { std::lock_guard lock(mutex_); is_initialized_ = false; + + if (sink_event_pipe_) { + ecore_pipe_del(sink_event_pipe_); + } + event_sink_ = nullptr; event_channel_->SetStreamHandler(nullptr); @@ -384,7 +435,7 @@ void VideoPlayer::SendInitialized() { int duration = 0; int ret = player_get_duration(player_, &duration); if (ret != PLAYER_ERROR_NONE) { - event_sink_->Error("player_get_duration failed", get_error_message(ret)); + SendError("player_get_duration failed", get_error_message(ret)); return; } LOG_DEBUG("[VideoPlayer] Video duration: %d", duration); @@ -392,8 +443,7 @@ void VideoPlayer::SendInitialized() { int width = 0, height = 0; ret = player_get_video_size(player_, &width, &height); if (ret != PLAYER_ERROR_NONE) { - event_sink_->Error("player_get_video_size failed", - get_error_message(ret)); + SendError("player_get_video_size failed", get_error_message(ret)); return; } LOG_DEBUG("[VideoPlayer] Video width: %d, height: %d", width, height); @@ -401,8 +451,7 @@ void VideoPlayer::SendInitialized() { player_display_rotation_e rotation = PLAYER_DISPLAY_ROTATION_NONE; ret = player_get_display_rotation(player_, &rotation); if (ret != PLAYER_ERROR_NONE) { - event_sink_->Error("player_get_display_rotation failed", - get_error_message(ret)); + SendError("player_get_display_rotation failed", get_error_message(ret)); } else { LOG_DEBUG("[VideoPlayer] rotation: %s", RotationToString(rotation).c_str()); @@ -421,7 +470,7 @@ void VideoPlayer::SendInitialized() { {flutter::EncodableValue("width"), flutter::EncodableValue(width)}, {flutter::EncodableValue("height"), flutter::EncodableValue(height)}, }; - event_sink_->Success(flutter::EncodableValue(result)); + PushEvent(flutter::EncodableValue(result)); } } @@ -468,13 +517,10 @@ void VideoPlayer::OnPlayCompleted(void *data) { LOG_DEBUG("[VideoPlayer] Play completed."); auto *player = static_cast(data); - if (player->event_sink_) { - flutter::EncodableMap result = { - {flutter::EncodableValue("event"), - flutter::EncodableValue("completed")}, - }; - player->event_sink_->Success(flutter::EncodableValue(result)); - } + flutter::EncodableMap result = { + {flutter::EncodableValue("event"), flutter::EncodableValue("completed")}, + }; + player->PushEvent(flutter::EncodableValue(result)); player->Pause(); } @@ -483,10 +529,7 @@ void VideoPlayer::OnInterrupted(player_interrupted_code_e code, void *data) { LOG_ERROR("[VideoPlayer] Interrupt code: %d", code); auto *player = static_cast(data); - if (player->event_sink_) { - player->event_sink_->Error("Interrupted error", - "Video player has been interrupted."); - } + player->SendError("Interrupted error", "Video player has been interrupted."); } void VideoPlayer::OnError(int error_code, void *data) { @@ -494,10 +537,8 @@ void VideoPlayer::OnError(int error_code, void *data) { get_error_message(error_code)); auto *player = static_cast(data); - if (player->event_sink_) { - player->event_sink_->Error( - "Player error", std::string("Error: ") + get_error_message(error_code)); - } + player->SendError("Player error", + std::string("Error: ") + get_error_message(error_code)); } void VideoPlayer::OnVideoFrameDecoded(media_packet_h packet, void *data) { diff --git a/packages/video_player/tizen/src/video_player.h b/packages/video_player/tizen/src/video_player.h index 25af72d8e..d58ea6ba4 100644 --- a/packages/video_player/tizen/src/video_player.h +++ b/packages/video_player/tizen/src/video_player.h @@ -44,6 +44,10 @@ class VideoPlayer { int64_t GetTextureId() { return texture_id_; } private: + void SendPendingEvents(); + void PushEvent(const flutter::EncodableValue &encodable_value); + void SendError(const std::string &error_code, + const std::string &error_message); FlutterDesktopGpuSurfaceDescriptor *ObtainGpuSurface(size_t width, size_t height); @@ -89,6 +93,11 @@ class VideoPlayer { void *screensaver_handle_; ScreensaverResetTimeout screensaver_reset_timeout_; Ecore_Timer *timer_; + + Ecore_Pipe *sink_event_pipe_ = nullptr; + std::mutex queue_mutex_; + std::queue encodable_event_queue_; + std::queue> error_event_queue_; }; #endif // FLUTTER_PLUGIN_VIDEO_PLAYER_H_ diff --git a/packages/video_player_videohole/CHANGELOG.md b/packages/video_player_videohole/CHANGELOG.md index a9563e341..2c6d16f51 100644 --- a/packages/video_player_videohole/CHANGELOG.md +++ b/packages/video_player_videohole/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.3 + +* Fix event channel issue, sending messages from native to Flutter on the platform thread. + ## 0.1.2 * Increase the minimum Flutter version to 3.3. diff --git a/packages/video_player_videohole/README.md b/packages/video_player_videohole/README.md index 15bda9318..c2bb54393 100644 --- a/packages/video_player_videohole/README.md +++ b/packages/video_player_videohole/README.md @@ -12,7 +12,7 @@ To use this package, add `video_player_videohole` as a dependency in your `pubsp ```yaml dependencies: - video_player_videohole: ^0.1.1 + video_player_videohole: ^0.1.3 ``` Then you can import `video_player_videohole` in your Dart code: diff --git a/packages/video_player_videohole/pubspec.yaml b/packages/video_player_videohole/pubspec.yaml index 09bf84847..881e4da35 100644 --- a/packages/video_player_videohole/pubspec.yaml +++ b/packages/video_player_videohole/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_videohole description: Flutter plugin for displaying inline video on Tizen TV devices. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/video_player_videohole -version: 0.1.2 +version: 0.1.3 environment: sdk: ">=2.18.0 <4.0.0" diff --git a/packages/video_player_videohole/tizen/src/video_player.cc b/packages/video_player_videohole/tizen/src/video_player.cc index 7c2f12e16..85786ed37 100644 --- a/packages/video_player_videohole/tizen/src/video_player.cc +++ b/packages/video_player_videohole/tizen/src/video_player.cc @@ -17,7 +17,53 @@ static int64_t player_index = 1; VideoPlayer::VideoPlayer(flutter::PluginRegistrar *plugin_registrar, void *native_window) - : plugin_registrar_(plugin_registrar), native_window_(native_window) {} + : plugin_registrar_(plugin_registrar), native_window_(native_window) { + sink_event_pipe_ = ecore_pipe_add( + [](void *data, void *buffer, unsigned int nbyte) -> void { + auto *self = static_cast(data); + self->SendPendingEvents(); + }, + this); +} + +void VideoPlayer::SendPendingEvents() { + std::lock_guard lock(queue_mutex_); + while (!encodable_event_queue_.empty()) { + if (event_sink_) { + event_sink_->Success(encodable_event_queue_.front()); + } + encodable_event_queue_.pop(); + } + + while (!error_event_queue_.empty()) { + if (event_sink_) { + event_sink_->Error(error_event_queue_.front().first, + error_event_queue_.front().second); + } + error_event_queue_.pop(); + } +} + +void VideoPlayer::PushEvent(const flutter::EncodableValue &encodable_value) { + if (!event_sink_) { + LOG_ERROR("[VideoPlayer] event sink is nullptr."); + return; + } + std::lock_guard lock(queue_mutex_); + encodable_event_queue_.push(encodable_value); + ecore_pipe_write(sink_event_pipe_, nullptr, 0); +} + +void VideoPlayer::SendError(const std::string &error_code, + const std::string &error_message) { + if (!event_sink_) { + LOG_ERROR("[VideoPlayer] event sink is nullptr."); + return; + } + std::lock_guard lock(queue_mutex_); + error_event_queue_.push(std::make_pair(error_code, error_message)); + ecore_pipe_write(sink_event_pipe_, nullptr, 0); +} bool VideoPlayer::SetDisplay() { int x = 0, y = 0, width = 0, height = 0; @@ -293,6 +339,9 @@ void VideoPlayer::Dispose() { is_initialized_ = false; event_sink_ = nullptr; event_channel_->SetStreamHandler(nullptr); + if (sink_event_pipe_) { + ecore_pipe_del(sink_event_pipe_); + } if (player_) { player_unprepare(player_); @@ -350,7 +399,7 @@ void VideoPlayer::SendInitialized() { int duration = 0; int ret = player_get_duration(player_, &duration); if (ret != PLAYER_ERROR_NONE) { - event_sink_->Error("player_get_duration failed", get_error_message(ret)); + SendError("player_get_duration failed", get_error_message(ret)); return; } LOG_INFO("[VideoPlayer] Video duration: %d", duration); @@ -358,8 +407,7 @@ void VideoPlayer::SendInitialized() { int width = 0, height = 0; ret = player_get_video_size(player_, &width, &height); if (ret != PLAYER_ERROR_NONE) { - event_sink_->Error("player_get_video_size failed", - get_error_message(ret)); + SendError("player_get_video_size failed", get_error_message(ret)); return; } LOG_INFO("[VideoPlayer] Video width: %d, height: %d", width, height); @@ -367,8 +415,7 @@ void VideoPlayer::SendInitialized() { player_display_rotation_e rotation = PLAYER_DISPLAY_ROTATION_NONE; ret = player_get_display_rotation(player_, &rotation); if (ret != PLAYER_ERROR_NONE) { - event_sink_->Error("player_get_display_rotation failed", - get_error_message(ret)); + SendError("player_get_display_rotation failed", get_error_message(ret)); } else { if (rotation == PLAYER_DISPLAY_ROTATION_90 || rotation == PLAYER_DISPLAY_ROTATION_270) { @@ -385,53 +432,44 @@ void VideoPlayer::SendInitialized() { {flutter::EncodableValue("width"), flutter::EncodableValue(width)}, {flutter::EncodableValue("height"), flutter::EncodableValue(height)}, }; - event_sink_->Success(flutter::EncodableValue(result)); + PushEvent(flutter::EncodableValue(result)); } } void VideoPlayer::SendBufferingStart() { - if (event_sink_) { - flutter::EncodableMap result = { - {flutter::EncodableValue("event"), - flutter::EncodableValue("bufferingStart")}, - }; - event_sink_->Success(flutter::EncodableValue(result)); - } + flutter::EncodableMap result = { + {flutter::EncodableValue("event"), + flutter::EncodableValue("bufferingStart")}, + }; + PushEvent(flutter::EncodableValue(result)); } void VideoPlayer::SendBufferingUpdate(int32_t value) { - if (event_sink_) { - flutter::EncodableMap result = { - {flutter::EncodableValue("event"), - flutter::EncodableValue("bufferingUpdate")}, - {flutter::EncodableValue("value"), flutter::EncodableValue(value)}, - }; - event_sink_->Success(flutter::EncodableValue(result)); - } + flutter::EncodableMap result = { + {flutter::EncodableValue("event"), + flutter::EncodableValue("bufferingUpdate")}, + {flutter::EncodableValue("value"), flutter::EncodableValue(value)}, + }; + PushEvent(flutter::EncodableValue(result)); } void VideoPlayer::SendBufferingEnd() { - if (event_sink_) { - flutter::EncodableMap result = { - {flutter::EncodableValue("event"), - flutter::EncodableValue("bufferingEnd")}, - }; - event_sink_->Success(flutter::EncodableValue(result)); - } + flutter::EncodableMap result = { + {flutter::EncodableValue("event"), + flutter::EncodableValue("bufferingEnd")}, + }; + PushEvent(flutter::EncodableValue(result)); } void VideoPlayer::SendSubtitleUpdate(int32_t duration, const std::string &text) { - if (event_sink_) { - flutter::EncodableMap result = { - {flutter::EncodableValue("event"), - flutter::EncodableValue("subtitleUpdate")}, - {flutter::EncodableValue("duration"), - flutter::EncodableValue(duration)}, - {flutter::EncodableValue("text"), flutter::EncodableValue(text)}, - }; - event_sink_->Success(flutter::EncodableValue(result)); - } + flutter::EncodableMap result = { + {flutter::EncodableValue("event"), + flutter::EncodableValue("subtitleUpdate")}, + {flutter::EncodableValue("duration"), flutter::EncodableValue(duration)}, + {flutter::EncodableValue("text"), flutter::EncodableValue(text)}, + }; + PushEvent(flutter::EncodableValue(result)); } void VideoPlayer::OnSubtitleUpdated(unsigned long duration, char *text, @@ -480,13 +518,11 @@ void VideoPlayer::OnPlayCompleted(void *data) { LOG_INFO("[VideoPlayer] Play completed."); VideoPlayer *player = static_cast(data); - if (player->event_sink_) { - flutter::EncodableMap result = { - {flutter::EncodableValue("event"), - flutter::EncodableValue("completed")}, - }; - player->event_sink_->Success(flutter::EncodableValue(result)); - } + flutter::EncodableMap result = { + {flutter::EncodableValue("event"), flutter::EncodableValue("completed")}, + }; + player->PushEvent(flutter::EncodableValue(result)); + player->Pause(); } @@ -495,10 +531,8 @@ void VideoPlayer::OnError(int error_code, void *data) { get_error_message(error_code)); VideoPlayer *player = static_cast(data); - if (player->event_sink_) { - player->event_sink_->Error( - "Player error", std::string("Error: ") + get_error_message(error_code)); - } + player->SendError("Player error", + std::string("Error: ") + get_error_message(error_code)); } void VideoPlayer::OnInterrupted(player_interrupted_code_e code, void *data) { @@ -506,10 +540,7 @@ void VideoPlayer::OnInterrupted(player_interrupted_code_e code, void *data) { VideoPlayer *player = static_cast(data); player->is_interrupted_ = true; - if (player->event_sink_) { - player->event_sink_->Error("Player interrupted", - "Video player has been interrupted."); - } + player->SendError("Player interrupted", "Video player has been interrupted."); } std::vector VideoPlayer::OnLicenseChallenge( diff --git a/packages/video_player_videohole/tizen/src/video_player.h b/packages/video_player_videohole/tizen/src/video_player.h index 077559c99..acdf97628 100644 --- a/packages/video_player_videohole/tizen/src/video_player.h +++ b/packages/video_player_videohole/tizen/src/video_player.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_PLUGIN_VIDEO_PLAYER_H_ #define FLUTTER_PLUGIN_VIDEO_PLAYER_H_ +#include #include #include #include @@ -12,6 +13,8 @@ #include #include +#include +#include #include #include @@ -49,6 +52,10 @@ class VideoPlayer { void RegisterSendPort(Dart_Port send_port) { send_port_ = send_port; } private: + void SendPendingEvents(); + void PushEvent(const flutter::EncodableValue &encodable_value); + void SendError(const std::string &error_code, + const std::string &error_message); bool SetDisplay(); void SetUpEventChannel(flutter::BinaryMessenger *messenger); void Initialize(); @@ -86,6 +93,11 @@ class VideoPlayer { SeekCompletedCallback on_seek_completed_; Dart_Port send_port_; + + Ecore_Pipe *sink_event_pipe_ = nullptr; + std::mutex queue_mutex_; + std::queue encodable_event_queue_; + std::queue> error_event_queue_; }; #endif // FLUTTER_PLUGIN_VIDEO_PLAYER_H_