Skip to content

Commit

Permalink
Fix non-platform thread issue in video_player_videohole
Browse files Browse the repository at this point in the history
  • Loading branch information
hyue7 committed Oct 26, 2023
1 parent ca3e1a3 commit 2f49a25
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 56 deletions.
4 changes: 4 additions & 0 deletions packages/video_player_videohole/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
2 changes: 1 addition & 1 deletion packages/video_player_videohole/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion packages/video_player_videohole/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
139 changes: 85 additions & 54 deletions packages/video_player_videohole/tizen/src/video_player.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<VideoPlayer *>(data);
self->SendPendingEvents();
},
this);
}

void VideoPlayer::SendPendingEvents() {
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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;
Expand Down Expand Up @@ -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_);
Expand Down Expand Up @@ -350,25 +399,23 @@ 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);

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);

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) {
Expand All @@ -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,
Expand Down Expand Up @@ -480,13 +518,11 @@ void VideoPlayer::OnPlayCompleted(void *data) {
LOG_INFO("[VideoPlayer] Play completed.");

VideoPlayer *player = static_cast<VideoPlayer *>(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();
}

Expand All @@ -495,21 +531,16 @@ void VideoPlayer::OnError(int error_code, void *data) {
get_error_message(error_code));

VideoPlayer *player = static_cast<VideoPlayer *>(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) {
LOG_ERROR("[VideoPlayer] Interrupt code: %d", code);

VideoPlayer *player = static_cast<VideoPlayer *>(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<uint8_t> VideoPlayer::OnLicenseChallenge(
Expand Down
12 changes: 12 additions & 0 deletions packages/video_player_videohole/tizen/src/video_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
#ifndef FLUTTER_PLUGIN_VIDEO_PLAYER_H_
#define FLUTTER_PLUGIN_VIDEO_PLAYER_H_

#include <Ecore.h>
#include <dart_api_dl.h>
#include <flutter/encodable_value.h>
#include <flutter/event_channel.h>
#include <flutter/plugin_registrar.h>
#include <player.h>

#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <vector>

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<flutter::EncodableValue> encodable_event_queue_;
std::queue<std::pair<std::string, std::string>> error_event_queue_;
};

#endif // FLUTTER_PLUGIN_VIDEO_PLAYER_H_

0 comments on commit 2f49a25

Please sign in to comment.