Skip to content

Upgrade flutter webrtc to 1.3.1#993

Draft
xiaowei-guan wants to merge 6 commits intoflutter-tizen:masterfrom
xiaowei-guan:upgrade_webrtc
Draft

Upgrade flutter webrtc to 1.3.1#993
xiaowei-guan wants to merge 6 commits intoflutter-tizen:masterfrom
xiaowei-guan:upgrade_webrtc

Conversation

@xiaowei-guan
Copy link
Copy Markdown
Contributor

No description provided.

@xiaowei-guan xiaowei-guan marked this pull request as draft April 15, 2026 10:07
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the flutter_webrtc dependency to version 1.3.1 and introduces a TaskRunner interface to facilitate thread-safe event dispatching. New features include setVolume for audio tracks, dataChannelGetBufferedAmount, and configurable RTC logging severity. The refactor propagates the TaskRunner through various observers and managers and updates several WebRTC internal headers. Feedback identifies critical issues including a use-after-free vulnerability in setVolume, the lack of initialization for the task_runner_ member, and a dangling pointer risk with a static global logging proxy. Further improvements are requested regarding the robustness of the maybeFindDouble helper, adherence to C++ casting standards, and the restoration of a check for defined statistics members.

Comment on lines +545 to +559
RTCMediaTrack* track = MediaTrackForId(trackId);
if (nullptr == track) {
result->Error("setVolume", "setVolume() Unable to find provided track");
return;
}

std::string kind = track->kind().std_string();
if (0 != kind.compare("audio")) {
result->Error("setVolume",
"setVolume() Only audio tracks can have volume set");
return;
}

auto audioTrack = static_cast<RTCAudioTrack*>(track);
audioTrack->SetVolume(volume.value());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Assigning the result of MediaTrackForId (which returns a scoped_refptr) to a raw pointer RTCMediaTrack* is dangerous. The temporary scoped_refptr returned by the function will be destroyed at the end of the assignment statement, potentially decrementing the reference count to zero and deleting the track object. This leads to a use-after-free vulnerability when track is accessed later. Always store the result in a scoped_refptr to keep the object alive.

Suggested change
RTCMediaTrack* track = MediaTrackForId(trackId);
if (nullptr == track) {
result->Error("setVolume", "setVolume() Unable to find provided track");
return;
}
std::string kind = track->kind().std_string();
if (0 != kind.compare("audio")) {
result->Error("setVolume",
"setVolume() Only audio tracks can have volume set");
return;
}
auto audioTrack = static_cast<RTCAudioTrack*>(track);
audioTrack->SetVolume(volume.value());
scoped_refptr<RTCMediaTrack> track = MediaTrackForId(trackId);
if (track == nullptr) {
result->Error("setVolume", "setVolume() Unable to find provided track");
return;
}
std::string kind = track->kind().std_string();
if (0 != kind.compare("audio")) {
result->Error("setVolume",
"setVolume() Only audio tracks can have volume set");
return;
}
auto audioTrack = static_cast<RTCAudioTrack*>(track.get());
audioTrack->SetVolume(volume.value());

std::unique_ptr<FlutterWebRTC> webrtc_;
BinaryMessenger* messenger_;
TextureRegistrar* textures_;
std::unique_ptr<TaskRunner> task_runner_;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The task_runner_ member is added but never initialized in the FlutterWebRtcTizenPlugin constructor. Consequently, task_runner() returns nullptr. This causes EventChannelProxyImpl::PostEvent to call sink_->Success directly on the current thread. Since WebRTC callbacks often occur on background threads and Flutter's EventSink must be used on the platform thread, this will lead to crashes. A concrete implementation of TaskRunner (e.g., using Tizen's ecore_main_loop_thread_safe_call_async) must be instantiated and assigned here.


namespace flutter_webrtc_plugin {

static EventChannelProxy* eventChannelProxy = nullptr;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The static global eventChannelProxy is a raw pointer to an object owned by FlutterWebRTCBase. If the plugin is destroyed and re-initialized, or if a log message arrives after the plugin is disposed, this pointer will be dangling. This will cause a crash in the logging callback captured in initLoggerCallback. Ensure the log sink is removed and the pointer is cleared in the plugin's destructor.

Comment on lines +96 to +102
inline std::optional<double> maybeFindDouble(const EncodableMap& map,
const std::string& key) {
auto it = map.find(EncodableValue(key));
if (it != map.end() && TypeIs<double>(it->second))
return GetValue<double>(it->second);
return std::nullopt;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The maybeFindDouble helper only checks for the double type. However, Flutter's StandardMessageCodec may encode whole numbers as int or int32_t. To be robust and consistent with findDouble, this helper should also handle integer types.

inline std::optional<double> maybeFindDouble(const EncodableMap& map,
                                             const std::string& key) {
  auto it = map.find(EncodableValue(key));
  if (it != map.end()) {
    if (TypeIs<double>(it->second)) return GetValue<double>(it->second);
    if (TypeIs<int>(it->second)) return static_cast<double>(GetValue<int>(it->second));
  }
  return std::nullopt;
}

RTCDataChannel* data_channel, std::unique_ptr<MethodResultProxy> result) {
EncodableMap params;
params[EncodableValue("bufferedAmount")] =
EncodableValue((int64_t)data_channel->buffered_amount());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Avoid using C-style casts. Use static_cast instead, as per the Google C++ Style Guide followed in this repository.

Suggested change
EncodableValue((int64_t)data_channel->buffered_amount());
EncodableValue(static_cast<int64_t>(data_channel->buffered_amount()));
References
  1. C++ code should follow the Google C++ Style Guide, which prefers C++-style casts over C-style casts. (link)

Comment on lines 967 to 970
auto members = stats->Members();
for (int i = 0; i < members.size(); i++) {
auto member = members[i];
if (!member->IsDefined()) {
continue;
}
switch (member->GetType()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The check !member->IsDefined() was removed. In WebRTC, statistics members may be undefined, and attempting to access their values without checking can lead to incorrect data or undefined behavior. It is safer to keep this check.

Suggested change
auto members = stats->Members();
for (int i = 0; i < members.size(); i++) {
auto member = members[i];
if (!member->IsDefined()) {
continue;
}
switch (member->GetType()) {
auto members = stats->Members();
for (int i = 0; i < members.size(); i++) {
auto member = members[i];
if (!member->IsDefined()) {
continue;
}
switch (member->GetType()) {

- Update minimum Flutter and Dart version to 3.13 and 3.1
- Fix analyze issue
- Update code format
- Adds compatibility with `http` 1.0 in example
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant