diff --git a/packages/flutter_webrtc/CHANGELOG.md b/packages/flutter_webrtc/CHANGELOG.md index d699e1a3a..37db5663c 100644 --- a/packages/flutter_webrtc/CHANGELOG.md +++ b/packages/flutter_webrtc/CHANGELOG.md @@ -1,9 +1,12 @@ ## NEXT +## 0.2.0 + * 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. +* Update flutter_webrtc to 1.3.1. ## 0.1.3 diff --git a/packages/flutter_webrtc/README.md b/packages/flutter_webrtc/README.md index 1c7d8bee2..8be68b1cc 100644 --- a/packages/flutter_webrtc/README.md +++ b/packages/flutter_webrtc/README.md @@ -40,8 +40,8 @@ For other Tizen devices : ```yaml dependencies: - flutter_webrtc: ^0.9.46 - flutter_webrtc_tizen: ^0.1.3 + flutter_webrtc: ^1.3.1 + flutter_webrtc_tizen: ^0.2.0 ``` ## Functionality diff --git a/packages/flutter_webrtc/example/flutter_webrtc_demo/pubspec.yaml b/packages/flutter_webrtc/example/flutter_webrtc_demo/pubspec.yaml index 4b35d885d..4c493d88f 100644 --- a/packages/flutter_webrtc/example/flutter_webrtc_demo/pubspec.yaml +++ b/packages/flutter_webrtc/example/flutter_webrtc_demo/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: cupertino_icons: ^1.0.3 flutter: sdk: flutter - flutter_webrtc: 0.9.46 # Use a fixed version due to build errors. + flutter_webrtc: ^1.4.1 flutter_webrtc_tizen: path: ../../ http: ">=0.13.0 <2.0.0" diff --git a/packages/flutter_webrtc/example/flutter_webrtc_example/pubspec.yaml b/packages/flutter_webrtc/example/flutter_webrtc_example/pubspec.yaml index ba0c58cf0..d0ca5cc62 100644 --- a/packages/flutter_webrtc/example/flutter_webrtc_example/pubspec.yaml +++ b/packages/flutter_webrtc/example/flutter_webrtc_example/pubspec.yaml @@ -3,21 +3,24 @@ description: Demonstrates how to use the webrtc plugin. publish_to: "none" environment: - sdk: ">=3.1.0 <4.0.0" + sdk: ">=3.3.0 <4.0.0" flutter: ">=3.13.0" dependencies: + cupertino_icons: ^1.0.2 flutter: sdk: flutter flutter_background: ^1.0.0 - flutter_webrtc: 0.9.46 # Use a fixed version due to build errors. + flutter_webrtc: ^1.4.1 flutter_webrtc_tizen: path: ../../ + gallery_saver_plus: 3.2.4 path_provider: ^2.0.7 path_provider_tizen: ^2.0.2 permission_handler: ^10.4.3 permission_handler_tizen: ^1.3.0 - web: ^0.3.0 + sdp_transform: ^0.3.2 + web: ^1.0.0 dev_dependencies: flutter_test: diff --git a/packages/flutter_webrtc/pubspec.yaml b/packages/flutter_webrtc/pubspec.yaml index 195432d30..b1b56e547 100644 --- a/packages/flutter_webrtc/pubspec.yaml +++ b/packages/flutter_webrtc/pubspec.yaml @@ -2,10 +2,10 @@ name: flutter_webrtc_tizen homepage: https://github.com/flutter-tizen/plugins description: Flutter WebRTC plugin for Tizen, based on GoogleWebRTC. repository: https://github.com/flutter-tizen/plugins/tree/master/packages/flutter_webrtc -version: 0.1.3 +version: 0.2.0 environment: - sdk: ">=3.1.0 <4.0.0" + sdk: ">=3.3.0 <4.0.0" flutter: ">=3.13.0" flutter: diff --git a/packages/flutter_webrtc/tizen/inc/flutter_common.h b/packages/flutter_webrtc/tizen/inc/flutter_common.h index 2b4231110..7d7798444 100644 --- a/packages/flutter_webrtc/tizen/inc/flutter_common.h +++ b/packages/flutter_webrtc/tizen/inc/flutter_common.h @@ -12,6 +12,9 @@ #include #include +#include +#include +#include #include typedef flutter::EncodableValue EncodableValue; @@ -26,6 +29,8 @@ typedef flutter::EventSink EventSink; typedef flutter::MethodCall MethodCall; typedef flutter::MethodResult MethodResult; +class TaskRunner; + // foo.StringValue() becomes std::get(foo) // foo.IsString() becomes std::holds_alternative(foo) @@ -88,6 +93,14 @@ inline double findDouble(const EncodableMap& map, const std::string& key) { return 0.0; } +inline std::optional maybeFindDouble(const EncodableMap& map, + const std::string& key) { + auto it = map.find(EncodableValue(key)); + if (it != map.end() && TypeIs(it->second)) + return GetValue(it->second); + return std::nullopt; +} + inline std::vector findVector(const EncodableMap& map, const std::string& key) { auto it = map.find(EncodableValue(key)); @@ -161,7 +174,8 @@ class MethodResultProxy { class EventChannelProxy { public: static std::unique_ptr Create( - BinaryMessenger* messenger, const std::string& channelName); + BinaryMessenger* messenger, TaskRunner* task_runner, + const std::string& channelName); virtual ~EventChannelProxy() = default; diff --git a/packages/flutter_webrtc/tizen/inc/flutter_data_channel.h b/packages/flutter_webrtc/tizen/inc/flutter_data_channel.h index 0a7e4e9ea..a0242d1ee 100644 --- a/packages/flutter_webrtc/tizen/inc/flutter_data_channel.h +++ b/packages/flutter_webrtc/tizen/inc/flutter_data_channel.h @@ -10,6 +10,7 @@ class FlutterRTCDataChannelObserver : public RTCDataChannelObserver { public: FlutterRTCDataChannelObserver(scoped_refptr data_channel, BinaryMessenger* messenger, + TaskRunner* task_runner, const std::string& channel_name); virtual ~FlutterRTCDataChannelObserver(); @@ -38,6 +39,9 @@ class FlutterDataChannel { const EncodableValue& data, std::unique_ptr); + void DataChannelGetBufferedAmount(RTCDataChannel* data_channel, + std::unique_ptr result); + void DataChannelClose(RTCDataChannel* data_channel, const std::string& data_channel_uuid, std::unique_ptr); diff --git a/packages/flutter_webrtc/tizen/inc/flutter_data_packet_cryptor.h b/packages/flutter_webrtc/tizen/inc/flutter_data_packet_cryptor.h new file mode 100644 index 000000000..c0b607ca9 --- /dev/null +++ b/packages/flutter_webrtc/tizen/inc/flutter_data_packet_cryptor.h @@ -0,0 +1,39 @@ +#ifndef FLUTTER_WEBRTC_RTC_DATA_PACKET_CRYPTOR_HXX +#define FLUTTER_WEBRTC_RTC_DATA_PACKET_CRYPTOR_HXX + +#include "flutter_common.h" +#include "flutter_webrtc_base.h" +#include "rtc_data_packet_cryptor.h" + +namespace flutter_webrtc_plugin { + +class FlutterDataPacketCryptor { + public: + FlutterDataPacketCryptor(FlutterWebRTCBase* base) : base_(base) {} + + bool HandleDataPacketCryptorMethodCall( + const MethodCallProxy& method_call, + std::unique_ptr result, + std::unique_ptr* outResult); + + void CreateDataPacketCryptor(const EncodableMap& constraints, + std::unique_ptr result); + + void DataPacketCryptorDispose(const EncodableMap& constraints, + std::unique_ptr result); + + void DataPacketCryptorEncrypt(const EncodableMap& constraints, + std::unique_ptr result); + + void DataPacketCryptorDecrypt(const EncodableMap& constraints, + std::unique_ptr result); + + private: + FlutterWebRTCBase* base_; + std::map> + data_packet_cryptors_; +}; + +} // namespace flutter_webrtc_plugin + +#endif // FLUTTER_WEBRTC_RTC_DATA_PACKET_CRYPTOR_HXX diff --git a/packages/flutter_webrtc/tizen/inc/flutter_frame_capturer.h b/packages/flutter_webrtc/tizen/inc/flutter_frame_capturer.h new file mode 100644 index 000000000..c405778bf --- /dev/null +++ b/packages/flutter_webrtc/tizen/inc/flutter_frame_capturer.h @@ -0,0 +1,36 @@ +#ifndef FLUTTER_WEBRTC_RTC_FRAME_CAPTURER_HXX +#define FLUTTER_WEBRTC_RTC_FRAME_CAPTURER_HXX + +#include + +#include "flutter_common.h" +#include "flutter_webrtc_base.h" +#include "rtc_video_frame.h" +#include "rtc_video_renderer.h" + +namespace flutter_webrtc_plugin { + +using namespace libwebrtc; + +class FlutterFrameCapturer + : public RTCVideoRenderer> { + public: + FlutterFrameCapturer(RTCVideoTrack* track, std::string path); + + virtual void OnFrame(scoped_refptr frame) override; + + void CaptureFrame(std::unique_ptr result); + + private: + RTCVideoTrack* track_; + std::string path_; + std::mutex mutex_; + scoped_refptr frame_; + volatile bool catch_frame_; + + bool SaveFrame(); +}; + +} // namespace flutter_webrtc_plugin + +#endif // !FLUTTER_WEBRTC_RTC_FRAME_CAPTURER_HXX \ No newline at end of file diff --git a/packages/flutter_webrtc/tizen/inc/flutter_frame_cryptor.h b/packages/flutter_webrtc/tizen/inc/flutter_frame_cryptor.h old mode 100755 new mode 100644 index 2a04ac3f5..d73e239fb --- a/packages/flutter_webrtc/tizen/inc/flutter_frame_cryptor.h +++ b/packages/flutter_webrtc/tizen/inc/flutter_frame_cryptor.h @@ -10,8 +10,10 @@ namespace flutter_webrtc_plugin { class FlutterFrameCryptorObserver : public libwebrtc::RTCFrameCryptorObserver { public: FlutterFrameCryptorObserver(BinaryMessenger* messenger, + TaskRunner* task_runner, const std::string& channelName) - : event_channel_(EventChannelProxy::Create(messenger, channelName)) {} + : event_channel_( + EventChannelProxy::Create(messenger, task_runner, channelName)) {} void OnFrameCryptionStateChanged(const string participant_id, libwebrtc::RTCFrameCryptionState state); @@ -23,8 +25,12 @@ class FlutterFrameCryptor { public: FlutterFrameCryptor(FlutterWebRTCBase* base) : base_(base) {} - bool HandleFrameCryptorMethodCall(const MethodCallProxy& method_call, - std::unique_ptr result); + // Since this takes ownership of result, ownership will be passed back to + // 'outResult' if this function fails + bool HandleFrameCryptorMethodCall( + const MethodCallProxy& method_call, + std::unique_ptr result, + std::unique_ptr* outResult); void FrameCryptorFactoryCreateFrameCryptor( const EncodableMap& constraints, @@ -57,6 +63,7 @@ class FlutterFrameCryptor { void KeyProviderExportSharedKey(const EncodableMap& constraints, std::unique_ptr result); + void KeyProviderSetKey(const EncodableMap& constraints, std::unique_ptr result); @@ -91,7 +98,6 @@ class FlutterFrameCryptor { frame_cryptors_; std::map> frame_cryptor_observers_; - std::map> key_providers_; }; } // namespace flutter_webrtc_plugin diff --git a/packages/flutter_webrtc/tizen/inc/flutter_peerconnection.h b/packages/flutter_webrtc/tizen/inc/flutter_peerconnection.h index 469ed0fa0..470fcb047 100644 --- a/packages/flutter_webrtc/tizen/inc/flutter_peerconnection.h +++ b/packages/flutter_webrtc/tizen/inc/flutter_peerconnection.h @@ -11,6 +11,7 @@ class FlutterPeerConnectionObserver : public RTCPeerConnectionObserver { FlutterPeerConnectionObserver(FlutterWebRTCBase* base, scoped_refptr peerconnection, BinaryMessenger* messenger, + TaskRunner* task_runner, const std::string& channel_name, std::string& peerConnectionId); diff --git a/packages/flutter_webrtc/tizen/inc/flutter_utf8_sanitize.h b/packages/flutter_webrtc/tizen/inc/flutter_utf8_sanitize.h new file mode 100644 index 000000000..fd7d1201f --- /dev/null +++ b/packages/flutter_webrtc/tizen/inc/flutter_utf8_sanitize.h @@ -0,0 +1,15 @@ +#ifndef FLUTTER_WEBRTC_PLUGIN_FLUTTER_UTF8_SANITIZE_H_ +#define FLUTTER_WEBRTC_PLUGIN_FLUTTER_UTF8_SANITIZE_H_ + +#include + +namespace flutter_webrtc_plugin { + +// ADM/device buffers may not be valid UTF-8. Flutter StandardMessageCodec +// decodes as UTF-8; invalid bytes cause FormatException. Use before +// EncodableValue and when comparing ids from Dart. +std::string SanitizeUtf8ForFlutter(const std::string& input); + +} // namespace flutter_webrtc_plugin + +#endif // FLUTTER_WEBRTC_PLUGIN_FLUTTER_UTF8_SANITIZE_H_ diff --git a/packages/flutter_webrtc/tizen/inc/flutter_video_renderer.h b/packages/flutter_webrtc/tizen/inc/flutter_video_renderer.h index 7eb598ef3..07c0f96db 100644 --- a/packages/flutter_webrtc/tizen/inc/flutter_video_renderer.h +++ b/packages/flutter_webrtc/tizen/inc/flutter_video_renderer.h @@ -20,6 +20,7 @@ class FlutterVideoRenderer ~FlutterVideoRenderer(); void initialize(TextureRegistrar* registrar, BinaryMessenger* messenger, + TaskRunner* task_runner, std::unique_ptr texture, int64_t texture_id); diff --git a/packages/flutter_webrtc/tizen/inc/flutter_webrtc.h b/packages/flutter_webrtc/tizen/inc/flutter_webrtc.h index ee6dcce7d..8d01bb4f9 100644 --- a/packages/flutter_webrtc/tizen/inc/flutter_webrtc.h +++ b/packages/flutter_webrtc/tizen/inc/flutter_webrtc.h @@ -3,11 +3,13 @@ #include "flutter_common.h" #include "flutter_data_channel.h" +#include "flutter_data_packet_cryptor.h" #include "flutter_frame_cryptor.h" #include "flutter_media_stream.h" #include "flutter_peerconnection.h" #include "flutter_video_renderer.h" #include "libwebrtc.h" +#include "rtc_logging.h" namespace flutter_webrtc_plugin { @@ -18,6 +20,8 @@ class FlutterWebRTCPlugin : public flutter::Plugin { virtual BinaryMessenger* messenger() = 0; virtual TextureRegistrar* textures() = 0; + + virtual TaskRunner* task_runner() = 0; }; class FlutterWebRTC : public FlutterWebRTCBase, @@ -25,13 +29,18 @@ class FlutterWebRTC : public FlutterWebRTCBase, public FlutterMediaStream, public FlutterPeerConnection, public FlutterDataChannel, - public FlutterFrameCryptor { + public FlutterFrameCryptor, + public FlutterDataPacketCryptor { public: FlutterWebRTC(FlutterWebRTCPlugin* plugin); virtual ~FlutterWebRTC(); void HandleMethodCall(const MethodCallProxy& method_call, std::unique_ptr result); + + private: + void initLoggerCallback(RTCLoggingSeverity severity); + RTCLoggingSeverity str2LogSeverity(std::string str); }; } // namespace flutter_webrtc_plugin diff --git a/packages/flutter_webrtc/tizen/inc/flutter_webrtc_base.h b/packages/flutter_webrtc/tizen/inc/flutter_webrtc_base.h index 9cc094c32..0a0c893b0 100644 --- a/packages/flutter_webrtc/tizen/inc/flutter_webrtc_base.h +++ b/packages/flutter_webrtc/tizen/inc/flutter_webrtc_base.h @@ -11,14 +11,15 @@ #include "flutter_common.h" #include "libwebrtc.h" #include "rtc_audio_device.h" +#include "rtc_audio_processing.h" #include "rtc_dtmf_sender.h" +#include "rtc_frame_cryptor.h" #include "rtc_media_stream.h" #include "rtc_media_track.h" #include "rtc_mediaconstraints.h" #include "rtc_peerconnection.h" #include "rtc_peerconnection_factory.h" #include "rtc_video_device.h" -#include "uuidxx.h" namespace flutter_webrtc_plugin { @@ -36,20 +37,26 @@ class FlutterWebRTCBase { friend class FlutterDataChannel; friend class FlutterPeerConnectionObserver; friend class FlutterFrameCryptor; + friend class FlutterDataPacketCryptor; enum ParseConstraintType { kMandatory, kOptional }; public: - FlutterWebRTCBase(BinaryMessenger* messenger, TextureRegistrar* textures); + FlutterWebRTCBase(BinaryMessenger* messenger, TextureRegistrar* textures, + TaskRunner* task_runner); ~FlutterWebRTCBase(); + virtual scoped_refptr audio_processing() { + return audio_processing_; + } + + virtual scoped_refptr MediaTrackForId(const std::string& id); + std::string GenerateUUID(); RTCPeerConnection* PeerConnectionForId(const std::string& id); void RemovePeerConnectionForId(const std::string& id); - RTCMediaTrack* MediaTrackForId(const std::string& id); - void RemoveMediaTrackForId(const std::string& id); FlutterPeerConnectionObserver* PeerConnectionObserversForId( @@ -83,6 +90,9 @@ class FlutterWebRTCBase { libwebrtc::scoped_refptr GetRtpReceiverById( RTCPeerConnection* pc, std::string id); + libwebrtc::scoped_refptr GetKeyProviderForId( + const std::string& keyProviderId); + private: void ParseConstraints(const EncodableMap& src, scoped_refptr mediaConstraints, @@ -95,8 +105,10 @@ class FlutterWebRTCBase { scoped_refptr factory_; scoped_refptr audio_device_; scoped_refptr video_device_; + scoped_refptr audio_processing_; RTCConfiguration configuration_; + std::map> key_providers_; std::map> peerconnections_; std::map> local_streams_; std::map> local_tracks_; @@ -113,6 +125,7 @@ class FlutterWebRTCBase { protected: BinaryMessenger* messenger_; + TaskRunner* task_runner_; TextureRegistrar* textures_; std::unique_ptr event_channel_; }; diff --git a/packages/flutter_webrtc/tizen/inc/task_runner.h b/packages/flutter_webrtc/tizen/inc/task_runner.h new file mode 100644 index 000000000..9da019ca2 --- /dev/null +++ b/packages/flutter_webrtc/tizen/inc/task_runner.h @@ -0,0 +1,17 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef PACKAGES_FLUTTER_WEBRTC_TASK_RUNNER_H_ +#define PACKAGES_FLUTTER_WEBRTC_TASK_RUNNER_H_ + +#include + +using TaskClosure = std::function; + +class TaskRunner { + public: + virtual void EnqueueTask(TaskClosure task) = 0; + virtual ~TaskRunner() = default; +}; + +#endif // PACKAGES_FLUTTER_WEBRTC_TASK_RUNNER_H_ \ No newline at end of file diff --git a/packages/flutter_webrtc/tizen/inc/task_runner_tizen.h b/packages/flutter_webrtc/tizen/inc/task_runner_tizen.h new file mode 100644 index 000000000..fd71b7acc --- /dev/null +++ b/packages/flutter_webrtc/tizen/inc/task_runner_tizen.h @@ -0,0 +1,27 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef PACKAGES_FLUTTER_WEBRTC_TASK_RUNNER_TIZEN_H_ +#define PACKAGES_FLUTTER_WEBRTC_TASK_RUNNER_TIZEN_H_ + +#include + +#include +#include + +#include "task_runner.h" + +class TaskRunnerTizen : public TaskRunner { + public: + TaskRunnerTizen(); + ~TaskRunnerTizen() override; + + void EnqueueTask(TaskClosure task) override; + + private: + static void RunTask(void* data); + std::mutex tasks_mutex_; + std::queue tasks_; +}; + +#endif // PACKAGES_FLUTTER_WEBRTC_TASK_RUNNER_TIZEN_H_ \ No newline at end of file diff --git a/packages/flutter_webrtc/tizen/lib/aarch64/libwebrtc.so b/packages/flutter_webrtc/tizen/lib/aarch64/libwebrtc.so index c1276dbb5..cd9ac41b1 100755 Binary files a/packages/flutter_webrtc/tizen/lib/aarch64/libwebrtc.so and b/packages/flutter_webrtc/tizen/lib/aarch64/libwebrtc.so differ diff --git a/packages/flutter_webrtc/tizen/lib/armel/libwebrtc.so b/packages/flutter_webrtc/tizen/lib/armel/libwebrtc.so index 14e112f99..0825443a3 100755 Binary files a/packages/flutter_webrtc/tizen/lib/armel/libwebrtc.so and b/packages/flutter_webrtc/tizen/lib/armel/libwebrtc.so differ diff --git a/packages/flutter_webrtc/tizen/lib/i586/libwebrtc.so b/packages/flutter_webrtc/tizen/lib/i586/libwebrtc.so index a0b45ad83..e99f9f0a5 100755 Binary files a/packages/flutter_webrtc/tizen/lib/i586/libwebrtc.so and b/packages/flutter_webrtc/tizen/lib/i586/libwebrtc.so differ diff --git a/packages/flutter_webrtc/tizen/project_def.prop b/packages/flutter_webrtc/tizen/project_def.prop index 965541cbd..674028e33 100644 --- a/packages/flutter_webrtc/tizen/project_def.prop +++ b/packages/flutter_webrtc/tizen/project_def.prop @@ -15,7 +15,7 @@ USER_CPP_DEFS = FLUTTER_PLUGIN_IMPL USER_CPP_UNDEFS = # User includes -USER_INC_DIRS = inc src third_party/libwebrtc/include third_party/uuidxx +USER_INC_DIRS = inc src third_party/libwebrtc/include third_party/uuidxx third_party/svpng USER_INC_FILES = USER_CPP_INC_FILES = diff --git a/packages/flutter_webrtc/tizen/src/flutter_common.cc b/packages/flutter_webrtc/tizen/src/flutter_common.cc index 56e0fb34b..512dc5855 100644 --- a/packages/flutter_webrtc/tizen/src/flutter_common.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_common.cc @@ -1,5 +1,9 @@ #include "flutter_common.h" +#include + +#include "task_runner.h" + class MethodCallProxyImpl : public MethodCallProxy { public: explicit MethodCallProxyImpl(const MethodCall& method_call) @@ -66,19 +70,21 @@ std::unique_ptr MethodResultProxy::Create( class EventChannelProxyImpl : public EventChannelProxy { public: - EventChannelProxyImpl(BinaryMessenger* messenger, + EventChannelProxyImpl(BinaryMessenger* messenger, TaskRunner* task_runner, const std::string& channelName) : channel_(std::make_unique( messenger, channelName, - &flutter::StandardMethodCodec::GetInstance())) { + &flutter::StandardMethodCodec::GetInstance())), + task_runner_(task_runner) { auto handler = std::make_unique< flutter::StreamHandlerFunctions>( [&](const EncodableValue* arguments, std::unique_ptr>&& events) -> std::unique_ptr> { sink_ = std::move(events); + std::weak_ptr weak_sink = sink_; for (auto& event : event_queue_) { - sink_->Success(event); + PostEvent(event); } event_queue_.clear(); on_listen_called_ = true; @@ -97,7 +103,7 @@ class EventChannelProxyImpl : public EventChannelProxy { void Success(const EncodableValue& event, bool cache_event = true) override { if (on_listen_called_) { - sink_->Success(event); + PostEvent(event); } else { if (cache_event) { event_queue_.push_back(event); @@ -105,14 +111,31 @@ class EventChannelProxyImpl : public EventChannelProxy { } } + void PostEvent(const EncodableValue& event) { + if (task_runner_) { + std::weak_ptr weak_sink = sink_; + task_runner_->EnqueueTask([weak_sink, event]() { + auto sink = weak_sink.lock(); + if (sink) { + sink->Success(event); + } + }); + } else { + sink_->Success(event); + } + } + private: std::unique_ptr channel_; - std::unique_ptr sink_; + std::shared_ptr> sink_; std::list event_queue_; bool on_listen_called_ = false; + TaskRunner* task_runner_; }; std::unique_ptr EventChannelProxy::Create( - BinaryMessenger* messenger, const std::string& channelName) { - return std::make_unique(messenger, channelName); -} + BinaryMessenger* messenger, TaskRunner* task_runner, + const std::string& channelName) { + return std::make_unique(messenger, task_runner, + channelName); +} \ No newline at end of file diff --git a/packages/flutter_webrtc/tizen/src/flutter_data_channel.cc b/packages/flutter_webrtc/tizen/src/flutter_data_channel.cc index d07fc3585..ce5f1a70a 100644 --- a/packages/flutter_webrtc/tizen/src/flutter_data_channel.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_data_channel.cc @@ -6,8 +6,9 @@ namespace flutter_webrtc_plugin { FlutterRTCDataChannelObserver::FlutterRTCDataChannelObserver( scoped_refptr data_channel, BinaryMessenger* messenger, - const std::string& channelName) - : event_channel_(EventChannelProxy::Create(messenger, channelName)), + TaskRunner* task_runner, const std::string& channelName) + : event_channel_( + EventChannelProxy::Create(messenger, task_runner, channelName)), data_channel_(data_channel) { data_channel_->RegisterObserver(this); } @@ -51,7 +52,7 @@ void FlutterDataChannel::CreateDataChannel( std::unique_ptr observer( new FlutterRTCDataChannelObserver(data_channel, base_->messenger_, - event_channel)); + base_->task_runner_, event_channel)); base_->lock(); base_->data_channel_observers_[uuid] = std::move(observer); @@ -81,6 +82,14 @@ void FlutterDataChannel::DataChannelSend( result->Success(); } +void FlutterDataChannel::DataChannelGetBufferedAmount( + RTCDataChannel* data_channel, std::unique_ptr result) { + EncodableMap params; + params[EncodableValue("bufferedAmount")] = + EncodableValue(static_cast(data_channel->buffered_amount())); + result->Success(EncodableValue(params)); +} + void FlutterDataChannel::DataChannelClose( RTCDataChannel* data_channel, const std::string& data_channel_uuid, std::unique_ptr result) { diff --git a/packages/flutter_webrtc/tizen/src/flutter_data_packet_cryptor.cc b/packages/flutter_webrtc/tizen/src/flutter_data_packet_cryptor.cc new file mode 100644 index 000000000..2417b58c4 --- /dev/null +++ b/packages/flutter_webrtc/tizen/src/flutter_data_packet_cryptor.cc @@ -0,0 +1,204 @@ +#include "flutter_data_packet_cryptor.h" + +#include "base/scoped_ref_ptr.h" + +namespace flutter_webrtc_plugin { + +bool FlutterDataPacketCryptor::HandleDataPacketCryptorMethodCall( + const MethodCallProxy& method_call, + std::unique_ptr result, + std::unique_ptr* outResult) { + const std::string& method_name = method_call.method_name(); + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null arguments received"); + return true; + } + const EncodableMap params = GetValue(*method_call.arguments()); + if (method_name == "createDataPacketCryptor") { + CreateDataPacketCryptor(params, std::move(result)); + return true; + } else if (method_name == "dataPacketCryptorDispose") { + DataPacketCryptorDispose(params, std::move(result)); + return true; + } else if (method_name == "dataPacketCryptorEncrypt") { + DataPacketCryptorEncrypt(params, std::move(result)); + return true; + } else if (method_name == "dataPacketCryptorDecrypt") { + DataPacketCryptorDecrypt(params, std::move(result)); + return true; + } + *outResult = std::move(result); + return false; +} + +libwebrtc::FrameCryptorAlgorithm KeyDerivationAlgorithmFromInt(int algorithm) { + switch (algorithm) { + case 0: + return libwebrtc::FrameCryptorAlgorithm::kAesGcm; + case 1: + return libwebrtc::FrameCryptorAlgorithm::kAesCbc; + default: + return libwebrtc::FrameCryptorAlgorithm::kAesGcm; + } +} + +void FlutterDataPacketCryptor::CreateDataPacketCryptor( + const EncodableMap& constraints, + std::unique_ptr result) { + std::string keyProviderId = findString(constraints, "keyProviderId"); + if (keyProviderId.empty()) { + result->Error("createDataPacketCryptor", + "createDataPacketCryptor() keyProviderId is null or empty"); + return; + } + int algorithm = findInt(constraints, "algorithm"); + + if (algorithm < 0) { + result->Error("createDataPacketCryptor", + "createDataPacketCryptor() algorithm is invalid"); + return; + } + + auto keyProvider = base_->key_providers_[keyProviderId]; + if (keyProvider == nullptr) { + result->Error("createDataPacketCryptor", + "createDataPacketCryptor() keyProvider is null"); + return; + } + std::string uuid = base_->GenerateUUID(); + data_packet_cryptors_[uuid] = libwebrtc::RTCDataPacketCryptor::Create( + keyProvider, KeyDerivationAlgorithmFromInt(algorithm)); + EncodableMap params; + params[EncodableValue("dataCryptorId")] = uuid; + result->Success(EncodableValue(params)); +} +void FlutterDataPacketCryptor::DataPacketCryptorDispose( + const EncodableMap& constraints, + std::unique_ptr result) { + std::string dataCryptorId = findString(constraints, "dataCryptorId"); + if (dataCryptorId.empty()) { + result->Error("dataPacketCryptorDispose", + "dataPacketCryptorDispose() dataCryptorId is null or empty"); + return; + } + auto dataCryptor = data_packet_cryptors_[dataCryptorId]; + if (dataCryptor == nullptr) { + result->Error("dataPacketCryptorDispose", + "dataPacketCryptorDispose() dataCryptor is null"); + return; + } + data_packet_cryptors_.erase(dataCryptorId); + + result->Success(); +} + +void FlutterDataPacketCryptor::DataPacketCryptorEncrypt( + const EncodableMap& constraints, + std::unique_ptr result) { + std::string dataCryptorId = findString(constraints, "dataCryptorId"); + if (dataCryptorId.empty()) { + result->Error("dataPacketCryptorEncrypt", + "dataPacketCryptorEncrypt() dataCryptorId is null or empty"); + return; + } + + auto dataCryptor = data_packet_cryptors_[dataCryptorId]; + if (dataCryptor == nullptr) { + result->Error("dataPacketCryptorEncrypt", + "dataPacketCryptorEncrypt() dataCryptor is null"); + return; + } + + std::string participantId = findString(constraints, "participantId"); + if (participantId.empty()) { + result->Error("dataPacketCryptorEncrypt", + "dataPacketCryptorEncrypt() participantId is null or empty"); + return; + } + int keyIndex = findInt(constraints, "keyIndex"); + if (keyIndex == -1) { + result->Error("dataPacketCryptorEncrypt", + "dataPacketCryptorEncrypt() keyIndex is null"); + return; + } + auto data = findVector(constraints, "data"); + if (data.size() == 0) { + result->Error("dataPacketCryptorEncrypt", + "dataPacketCryptorEncrypt() data is null or empty"); + return; + } + auto encryptedPacket = + dataCryptor->encrypt(participantId, keyIndex, vector(data)); + + if (encryptedPacket == nullptr) { + result->Error("dataPacketCryptorEncrypt", + "dataPacketCryptorEncrypt() encryption failed"); + return; + } + + EncodableMap params; + params[EncodableValue("data")] = + EncodableValue(encryptedPacket->data().std_vector()); + params[EncodableValue("iv")] = + EncodableValue(encryptedPacket->iv().std_vector()); + params[EncodableValue("keyIndex")] = + EncodableValue(encryptedPacket->key_index()); + result->Success(EncodableValue(params)); +} + +void FlutterDataPacketCryptor::DataPacketCryptorDecrypt( + const EncodableMap& constraints, + std::unique_ptr result) { + std::string dataCryptorId = findString(constraints, "dataCryptorId"); + if (dataCryptorId.empty()) { + result->Error("dataPacketCryptorDecrypt", + "dataPacketCryptorDecrypt() dataCryptorId is null or empty"); + return; + } + auto dataCryptor = data_packet_cryptors_[dataCryptorId]; + if (dataCryptor == nullptr) { + result->Error("dataPacketCryptorDecrypt", + "dataPacketCryptorDecrypt() dataCryptor is null"); + return; + } + std::string participantId = findString(constraints, "participantId"); + if (participantId.empty()) { + result->Error("dataPacketCryptorDecrypt", + "dataPacketCryptorDecrypt() participantId is null or empty"); + return; + } + int keyIndex = findInt(constraints, "keyIndex"); + if (keyIndex == -1) { + result->Error("dataPacketCryptorDecrypt", + "dataPacketCryptorDecrypt() keyIndex is null"); + return; + } + auto encryptedData = findVector(constraints, "data"); + if (encryptedData.size() == 0) { + result->Error("dataPacketCryptorDecrypt", + "dataPacketCryptorDecrypt() encrypted data is null or empty"); + return; + } + auto iv = findVector(constraints, "iv"); + if (iv.size() == 0) { + result->Error("dataPacketCryptorDecrypt", + "dataPacketCryptorDecrypt() iv is null or empty"); + return; + } + auto decryptedData = + dataCryptor->decrypt(participantId, keyIndex, + libwebrtc::EncryptedPacket::Create( + vector(encryptedData), + vector(iv), (uint8_t)keyIndex)); + if (encryptedData.size() != 0 && decryptedData.size() == 0) { + result->Error("dataPacketCryptorDecrypt", + "dataPacketCryptorDecrypt() decryption failed"); + return; + } + + EncodableMap params; + params[EncodableValue("data")] = EncodableValue(decryptedData.std_vector()); + result->Success(EncodableValue(params)); +} + +} // namespace flutter_webrtc_plugin \ No newline at end of file diff --git a/packages/flutter_webrtc/tizen/src/flutter_frame_capturer.cc b/packages/flutter_webrtc/tizen/src/flutter_frame_capturer.cc new file mode 100644 index 000000000..818df7d3e --- /dev/null +++ b/packages/flutter_webrtc/tizen/src/flutter_frame_capturer.cc @@ -0,0 +1,79 @@ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "flutter_frame_capturer.h" + +#include +#include + +#include "svpng.hpp" + +namespace flutter_webrtc_plugin { + +FlutterFrameCapturer::FlutterFrameCapturer(RTCVideoTrack* track, + std::string path) { + track_ = track; + path_ = path; +} + +void FlutterFrameCapturer::OnFrame(scoped_refptr frame) { + if (frame_ != nullptr) { + return; + } + + frame_ = frame.get()->Copy(); + catch_frame_ = true; +} + +void FlutterFrameCapturer::CaptureFrame( + std::unique_ptr result) { + mutex_.lock(); + // Here init catch_frame_ flag + catch_frame_ = false; + + track_->AddRenderer(this); + // Here waiting for catch_frame_ is set to true + while (!catch_frame_) { + } + // Here unlock the mutex + mutex_.unlock(); + + mutex_.lock(); + track_->RemoveRenderer(this); + + bool success = SaveFrame(); + mutex_.unlock(); + + std::shared_ptr result_ptr(result.release()); + if (success) { + result_ptr->Success(); + } else { + result_ptr->Error("1", "Cannot save the frame as .png file"); + } +} + +bool FlutterFrameCapturer::SaveFrame() { + if (frame_ == nullptr) { + return false; + } + + int width = frame_.get()->width(); + int height = frame_.get()->height(); + int bytes_per_pixel = 4; + uint8_t* pixels = new uint8_t[width * height * bytes_per_pixel]; + + frame_.get()->ConvertToARGB(RTCVideoFrame::Type::kABGR, pixels, + /* unused */ -1, width, height); + + FILE* file = fopen(path_.c_str(), "wb"); + if (!file) { + return false; + } + + svpng(file, width, height, pixels, 1); + fclose(file); + return true; +} + +} // namespace flutter_webrtc_plugin \ No newline at end of file diff --git a/packages/flutter_webrtc/tizen/src/flutter_frame_cryptor.cc b/packages/flutter_webrtc/tizen/src/flutter_frame_cryptor.cc old mode 100755 new mode 100644 index 8caf7b730..2e703e8b9 --- a/packages/flutter_webrtc/tizen/src/flutter_frame_cryptor.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_frame_cryptor.cc @@ -4,14 +4,14 @@ namespace flutter_webrtc_plugin { -libwebrtc::Algorithm AlgorithmFromInt(int algorithm) { +libwebrtc::FrameCryptorAlgorithm AlgorithmFromInt(int algorithm) { switch (algorithm) { case 0: - return libwebrtc::Algorithm::kAesGcm; + return libwebrtc::FrameCryptorAlgorithm::kAesGcm; case 1: - return libwebrtc::Algorithm::kAesCbc; + return libwebrtc::FrameCryptorAlgorithm::kAesCbc; default: - return libwebrtc::Algorithm::kAesGcm; + return libwebrtc::FrameCryptorAlgorithm::kAesGcm; } } @@ -48,7 +48,8 @@ void FlutterFrameCryptorObserver::OnFrameCryptionStateChanged( bool FlutterFrameCryptor::HandleFrameCryptorMethodCall( const MethodCallProxy& method_call, - std::unique_ptr result) { + std::unique_ptr result, + std::unique_ptr* outResult) { const std::string& method_name = method_call.method_name(); if (!method_call.arguments()) { result->Error("Bad Arguments", "Null arguments received"); @@ -103,6 +104,7 @@ bool FlutterFrameCryptor::HandleFrameCryptorMethodCall( return true; } + *outResult = std::move(result); return false; } @@ -152,7 +154,7 @@ void FlutterFrameCryptor::FrameCryptorFactoryCreateFrameCryptor( return; } std::string uuid = base_->GenerateUUID(); - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (keyProvider == nullptr) { result->Error("FrameCryptorFactoryCreateFrameCryptorFailed", "keyProvider is null"); @@ -165,8 +167,8 @@ void FlutterFrameCryptor::FrameCryptorFactoryCreateFrameCryptor( std::string event_channel = "FlutterWebRTC/frameCryptorEvent" + uuid; scoped_refptr observer( - new RefCountedObject(base_->messenger_, - event_channel)); + new RefCountedObject( + base_->messenger_, base_->task_runner_, event_channel)); frameCryptor->RegisterRTCFrameCryptorObserver(observer); @@ -184,7 +186,7 @@ void FlutterFrameCryptor::FrameCryptorFactoryCreateFrameCryptor( return; } std::string uuid = base_->GenerateUUID(); - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; auto frameCryptor = libwebrtc::FrameCryptorFactory::frameCryptorFromRtpReceiver( base_->factory_, string(participantId), receiver, @@ -193,8 +195,8 @@ void FlutterFrameCryptor::FrameCryptorFactoryCreateFrameCryptor( std::string event_channel = "FlutterWebRTC/frameCryptorEvent" + uuid; scoped_refptr observer( - new RefCountedObject(base_->messenger_, - event_channel)); + new RefCountedObject( + base_->messenger_, base_->task_runner_, event_channel)); frameCryptor->RegisterRTCFrameCryptorObserver(observer.get()); @@ -349,6 +351,14 @@ void FlutterFrameCryptor::FrameCryptorFactoryCreateKeyProvider( auto failureTolerance = findInt(keyProviderOptions, "failureTolerance"); options.failure_tolerance = failureTolerance; + auto keyRingSize = findInt(keyProviderOptions, "keyRingSize"); + options.key_ring_size = keyRingSize; + + auto discardFrameWhenCryptorNotReady = + findBoolean(keyProviderOptions, "discardFrameWhenCryptorNotReady"); + options.discard_frame_when_cryptor_not_ready = + discardFrameWhenCryptorNotReady; + auto keyProvider = libwebrtc::KeyProvider::Create(&options); if (nullptr == keyProvider.get()) { result->Error("FrameCryptorFactoryCreateKeyProviderFailed", @@ -356,7 +366,7 @@ void FlutterFrameCryptor::FrameCryptorFactoryCreateKeyProvider( return; } auto uuid = base_->GenerateUUID(); - key_providers_[uuid] = keyProvider; + base_->key_providers_[uuid] = keyProvider; EncodableMap params; params[EncodableValue("keyProviderId")] = uuid; result->Success(EncodableValue(params)); @@ -371,7 +381,7 @@ void FlutterFrameCryptor::KeyProviderSetSharedKey( return; } - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (nullptr == keyProvider.get()) { result->Error("KeyProviderSetSharedKeyFailed", "keyProvider is null"); return; @@ -404,7 +414,7 @@ void FlutterFrameCryptor::KeyProviderRatchetSharedKey( return; } - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (nullptr == keyProvider.get()) { result->Error("KeyProviderRatchetSharedKeyFailed", "keyProvider is null"); return; @@ -432,7 +442,7 @@ void FlutterFrameCryptor::KeyProviderExportSharedKey( return; } - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (nullptr == keyProvider.get()) { result->Error("KeyProviderExportSharedKeyFailed", "keyProvider is null"); return; @@ -460,7 +470,7 @@ void FlutterFrameCryptor::KeyProviderExportKey( return; } - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (nullptr == keyProvider.get()) { result->Error("KeyProviderExportKeyFailed", "keyProvider is null"); return; @@ -494,7 +504,7 @@ void FlutterFrameCryptor::KeyProviderSetSifTrailer( return; } - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (nullptr == keyProvider.get()) { result->Error("KeyProviderSetSifTrailerFailed", "keyProvider is null"); return; @@ -521,7 +531,7 @@ void FlutterFrameCryptor::KeyProviderSetKey( return; } - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (nullptr == keyProvider.get()) { result->Error("KeyProviderSetKeyFailed", "keyProvider is null"); return; @@ -559,7 +569,7 @@ void FlutterFrameCryptor::KeyProviderRatchetKey( return; } - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (nullptr == keyProvider.get()) { result->Error("KeyProviderSetKeysFailed", "keyProvider is null"); return; @@ -593,12 +603,12 @@ void FlutterFrameCryptor::KeyProviderDispose( return; } - auto keyProvider = key_providers_[keyProviderId]; + auto keyProvider = base_->key_providers_[keyProviderId]; if (nullptr == keyProvider.get()) { result->Error("KeyProviderDisposeFailed", "keyProvider is null"); return; } - key_providers_.erase(keyProviderId); + base_->key_providers_.erase(keyProviderId); EncodableMap params; params[EncodableValue("result")] = "success"; result->Success(EncodableValue(params)); diff --git a/packages/flutter_webrtc/tizen/src/flutter_media_stream.cc b/packages/flutter_webrtc/tizen/src/flutter_media_stream.cc index 38ec5454e..b572646fe 100644 --- a/packages/flutter_webrtc/tizen/src/flutter_media_stream.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_media_stream.cc @@ -1,11 +1,37 @@ #include "flutter_media_stream.h" +#include "flutter_utf8_sanitize.h" + #define DEFAULT_WIDTH 1280 #define DEFAULT_HEIGHT 720 #define DEFAULT_FPS 30 namespace flutter_webrtc_plugin { +namespace { + +std::string SanitizeDeviceIdFromAudioBuffers(const char* name, + const char* guid) { + const std::string raw = (guid != nullptr && strlen(guid) > 0) + ? std::string(guid) + : std::string(name != nullptr ? name : ""); + return SanitizeUtf8ForFlutter(raw); +} + +std::string SanitizeLabel(const char* name) { + return SanitizeUtf8ForFlutter(std::string(name != nullptr ? name : "")); +} + +std::string SanitizeDeviceIdFromVideoBuffers(const char* name, + const char* guid) { + const std::string raw = (guid != nullptr && strlen(guid) > 0) + ? std::string(guid) + : std::string(name != nullptr ? name : ""); + return SanitizeUtf8ForFlutter(raw); +} + +} // namespace + FlutterMediaStream::FlutterMediaStream(FlutterWebRTCBase* base) : base_(base) { base_->audio_device_->OnDeviceChange([&] { EncodableMap info; @@ -129,7 +155,9 @@ void FlutterMediaStream::GetUserAudio(const EncodableMap& constraints, for (uint16_t i = 0; i < recording_devices; i++) { base_->audio_device_->RecordingDeviceName(i, strRecordingName, strRecordingGuid); - if (sourceId != "" && sourceId == strRecordingGuid) { + if (sourceId != "" && + sourceId == SanitizeDeviceIdFromAudioBuffers(strRecordingName, + strRecordingGuid)) { base_->audio_device_->SetRecordingDevice(i); } } @@ -137,7 +165,8 @@ void FlutterMediaStream::GetUserAudio(const EncodableMap& constraints, if (sourceId == "") { base_->audio_device_->RecordingDeviceName(0, strRecordingName, strRecordingGuid); - sourceId = strRecordingGuid; + sourceId = + SanitizeDeviceIdFromAudioBuffers(strRecordingName, strRecordingGuid); } char strPlayoutName[256]; @@ -145,7 +174,8 @@ void FlutterMediaStream::GetUserAudio(const EncodableMap& constraints, for (uint16_t i = 0; i < playout_devices; i++) { base_->audio_device_->PlayoutDeviceName(i, strPlayoutName, strPlayoutGuid); - if (deviceId != "" && deviceId == strPlayoutGuid) { + if (deviceId != "" && deviceId == SanitizeDeviceIdFromAudioBuffers( + strPlayoutName, strPlayoutGuid)) { base_->audio_device_->SetPlayoutDevice(i); } } @@ -167,7 +197,8 @@ void FlutterMediaStream::GetUserAudio(const EncodableMap& constraints, track_info[EncodableValue("enabled")] = EncodableValue(track->enabled()); EncodableMap settings; - settings[EncodableValue("deviceId")] = EncodableValue(sourceId); + settings[EncodableValue("deviceId")] = + EncodableValue(SanitizeUtf8ForFlutter(sourceId)); settings[EncodableValue("kind")] = EncodableValue("audioinput"); settings[EncodableValue("autoGainControl")] = EncodableValue(true); settings[EncodableValue("echoCancellation")] = EncodableValue(true); @@ -268,7 +299,8 @@ void FlutterMediaStream::GetUserVideo(const EncodableMap& constraints, for (int i = 0; i < nb_video_devices; i++) { base_->video_device_->GetDeviceName(i, strNameUTF8, 256, strGuidUTF8, 256); - if (sourceId != "" && sourceId == strGuidUTF8) { + if (sourceId != "" && sourceId == SanitizeDeviceIdFromVideoBuffers( + strNameUTF8, strGuidUTF8)) { video_capturer = base_->video_device_->Create(strNameUTF8, i, width, height, fps); break; @@ -279,7 +311,7 @@ void FlutterMediaStream::GetUserVideo(const EncodableMap& constraints, if (!video_capturer.get()) { base_->video_device_->GetDeviceName(0, strNameUTF8, 128, strGuidUTF8, 128); - sourceId = strGuidUTF8; + sourceId = SanitizeDeviceIdFromVideoBuffers(strNameUTF8, strGuidUTF8); video_capturer = base_->video_device_->Create(strNameUTF8, 0, width, height, fps); } @@ -305,7 +337,8 @@ void FlutterMediaStream::GetUserVideo(const EncodableMap& constraints, info[EncodableValue("enabled")] = EncodableValue(track->enabled()); EncodableMap settings; - settings[EncodableValue("deviceId")] = EncodableValue(sourceId); + settings[EncodableValue("deviceId")] = + EncodableValue(SanitizeUtf8ForFlutter(sourceId)); settings[EncodableValue("kind")] = EncodableValue("videoinput"); settings[EncodableValue("width")] = EncodableValue(width); settings[EncodableValue("height")] = EncodableValue(height); @@ -330,10 +363,11 @@ void FlutterMediaStream::GetSources(std::unique_ptr result) { for (uint16_t i = 0; i < nb_audio_devices; i++) { base_->audio_device_->RecordingDeviceName(i, strNameUTF8, strGuidUTF8); + std::string device_id = + SanitizeDeviceIdFromAudioBuffers(strNameUTF8, strGuidUTF8); EncodableMap audio; - audio[EncodableValue("label")] = EncodableValue(std::string(strNameUTF8)); - audio[EncodableValue("deviceId")] = - EncodableValue(std::string(strGuidUTF8)); + audio[EncodableValue("label")] = EncodableValue(SanitizeLabel(strNameUTF8)); + audio[EncodableValue("deviceId")] = EncodableValue(device_id); audio[EncodableValue("facing")] = ""; audio[EncodableValue("kind")] = "audioinput"; sources.push_back(EncodableValue(audio)); @@ -342,10 +376,11 @@ void FlutterMediaStream::GetSources(std::unique_ptr result) { nb_audio_devices = base_->audio_device_->PlayoutDevices(); for (uint16_t i = 0; i < nb_audio_devices; i++) { base_->audio_device_->PlayoutDeviceName(i, strNameUTF8, strGuidUTF8); + std::string device_id = + SanitizeDeviceIdFromAudioBuffers(strNameUTF8, strGuidUTF8); EncodableMap audio; - audio[EncodableValue("label")] = EncodableValue(std::string(strNameUTF8)); - audio[EncodableValue("deviceId")] = - EncodableValue(std::string(strGuidUTF8)); + audio[EncodableValue("label")] = EncodableValue(SanitizeLabel(strNameUTF8)); + audio[EncodableValue("deviceId")] = EncodableValue(device_id); audio[EncodableValue("facing")] = ""; audio[EncodableValue("kind")] = "audiooutput"; sources.push_back(EncodableValue(audio)); @@ -355,9 +390,9 @@ void FlutterMediaStream::GetSources(std::unique_ptr result) { for (int i = 0; i < nb_video_devices; i++) { base_->video_device_->GetDeviceName(i, strNameUTF8, 128, strGuidUTF8, 128); EncodableMap video; - video[EncodableValue("label")] = EncodableValue(std::string(strNameUTF8)); - video[EncodableValue("deviceId")] = - EncodableValue(std::string(strGuidUTF8)); + video[EncodableValue("label")] = EncodableValue(SanitizeLabel(strNameUTF8)); + video[EncodableValue("deviceId")] = EncodableValue( + SanitizeDeviceIdFromVideoBuffers(strNameUTF8, strGuidUTF8)); video[EncodableValue("facing")] = i == 1 ? "front" : "back"; video[EncodableValue("kind")] = "videoinput"; sources.push_back(EncodableValue(video)); @@ -369,20 +404,23 @@ void FlutterMediaStream::GetSources(std::unique_ptr result) { void FlutterMediaStream::SelectAudioOutput( const std::string& device_id, std::unique_ptr result) { - char strPlayoutName[256]; - char strPlayoutGuid[256]; + char deviceName[256]; + char deviceGuid[256]; int playout_devices = base_->audio_device_->PlayoutDevices(); bool found = false; for (uint16_t i = 0; i < playout_devices; i++) { - base_->audio_device_->PlayoutDeviceName(i, strPlayoutName, strPlayoutGuid); - if (device_id != "" && device_id == strPlayoutGuid) { + base_->audio_device_->PlayoutDeviceName(i, deviceName, deviceGuid); + std::string cur_device_id = + SanitizeDeviceIdFromAudioBuffers(deviceName, deviceGuid); + if (device_id != "" && device_id == cur_device_id) { base_->audio_device_->SetPlayoutDevice(i); found = true; break; } } if (!found) { - result->Error("Bad Arguments", "Not found device id: " + device_id); + result->Error("Bad Arguments", + "Not found device id: " + SanitizeUtf8ForFlutter(device_id)); return; } result->Success(); @@ -390,21 +428,23 @@ void FlutterMediaStream::SelectAudioOutput( void FlutterMediaStream::SelectAudioInput( const std::string& device_id, std::unique_ptr result) { - char strPlayoutName[256]; - char strPlayoutGuid[256]; + char deviceName[256]; + char deviceGuid[256]; int playout_devices = base_->audio_device_->RecordingDevices(); bool found = false; for (uint16_t i = 0; i < playout_devices; i++) { - base_->audio_device_->RecordingDeviceName(i, strPlayoutName, - strPlayoutGuid); - if (device_id != "" && device_id == strPlayoutGuid) { + base_->audio_device_->RecordingDeviceName(i, deviceName, deviceGuid); + std::string cur_device_id = + SanitizeDeviceIdFromAudioBuffers(deviceName, deviceGuid); + if (device_id != "" && device_id == cur_device_id) { base_->audio_device_->SetRecordingDevice(i); found = true; break; } } if (!found) { - result->Error("Bad Arguments", "Not found device id: " + device_id); + result->Error("Bad Arguments", + "Not found device id: " + SanitizeUtf8ForFlutter(device_id)); return; } result->Success(); diff --git a/packages/flutter_webrtc/tizen/src/flutter_peerconnection.cc b/packages/flutter_webrtc/tizen/src/flutter_peerconnection.cc index 1130a333a..17fa8d570 100644 --- a/packages/flutter_webrtc/tizen/src/flutter_peerconnection.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_peerconnection.cc @@ -2,6 +2,7 @@ #include "base/scoped_ref_ptr.h" #include "flutter_data_channel.h" +#include "flutter_frame_capturer.h" #include "rtc_dtmf_sender.h" #include "rtc_rtp_parameters.h" @@ -107,6 +108,43 @@ const char* iceGatheringStateString(RTCIceGatheringState state) { return ""; } +double stringToBitratePriority(const std::string& priority) { + if (priority == "very-low") return 0.5; + if (priority == "low") return 1.0; + if (priority == "medium") return 2.0; + if (priority == "high") return 4.0; + return 1.0; +} + +std::string bitratePriorityToString(double bitratePriority) { + if (bitratePriority <= 0.5) return "very-low"; + if (bitratePriority <= 1.0) return "low"; + if (bitratePriority <= 2.0) return "medium"; + return "high"; +} + +libwebrtc::RTCPriority stringToRTCPriority(const std::string& priority) { + if (priority == "very-low") return libwebrtc::RTCPriority::kVeryLow; + if (priority == "low") return libwebrtc::RTCPriority::kLow; + if (priority == "medium") return libwebrtc::RTCPriority::kMedium; + if (priority == "high") return libwebrtc::RTCPriority::kHigh; + return libwebrtc::RTCPriority::kLow; +} + +std::string rtcPriorityToString(libwebrtc::RTCPriority priority) { + switch (priority) { + case libwebrtc::RTCPriority::kVeryLow: + return "very-low"; + case libwebrtc::RTCPriority::kLow: + return "low"; + case libwebrtc::RTCPriority::kMedium: + return "medium"; + case libwebrtc::RTCPriority::kHigh: + return "high"; + } + return "low"; +} + EncodableMap rtpParametersToMap( libwebrtc::scoped_refptr rtpParameters) { EncodableMap info; @@ -151,6 +189,10 @@ EncodableMap rtpParametersToMap( EncodableValue(encoding->scalability_mode().std_string()); map[EncodableValue("ssrc")] = EncodableValue(static_cast(encoding->ssrc())); + map[EncodableValue("priority")] = + EncodableValue(bitratePriorityToString(encoding->bitrate_priority())); + map[EncodableValue("networkPriority")] = + EncodableValue(rtcPriorityToString(encoding->network_priority())); encodings_info.push_back(EncodableValue(map)); } info[EncodableValue("encodings")] = EncodableValue(encodings_info); @@ -192,9 +234,9 @@ EncodableMap rtpParametersToMap( info[EncodableValue("degradationPreference")] = EncodableValue("balanced"); break; - case libwebrtc::RTCDegradationPreference::DISABLED: + case libwebrtc::RTCDegradationPreference::MAINTAIN_FRAMERATE_AND_RESOLUTION: info[EncodableValue("degradationPreference")] = - EncodableValue("disabled"); + EncodableValue("maintain-framerate-and-resolution"); break; default: info[EncodableValue("degradationPreference")] = @@ -336,7 +378,8 @@ void FlutterPeerConnection::CreateRTCPeerConnection( std::unique_ptr observer( new FlutterPeerConnectionObserver(base_, pc, base_->messenger_, - event_channel, uuid)); + base_->task_runner_, event_channel, + uuid)); base_->peerconnection_observers_[uuid] = std::move(observer); @@ -348,15 +391,15 @@ void FlutterPeerConnection::CreateRTCPeerConnection( void FlutterPeerConnection::RTCPeerConnectionClose( RTCPeerConnection* pc, const std::string& uuid, std::unique_ptr result) { - auto it = base_->peerconnections_.find(uuid); - if (it != base_->peerconnections_.end()) { - it->second->Close(); - base_->peerconnections_.erase(it); + auto it2 = base_->peerconnections_.find(uuid); + if (it2 != base_->peerconnections_.end()) { + it2->second->Close(); + base_->peerconnections_.erase(it2); } - auto it2 = base_->peerconnection_observers_.find(uuid); - if (it2 != base_->peerconnection_observers_.end()) - base_->peerconnection_observers_.erase(it2); + auto it = base_->peerconnection_observers_.find(uuid); + if (it != base_->peerconnection_observers_.end()) + base_->peerconnection_observers_.erase(it); result->Success(); } @@ -504,6 +547,8 @@ FlutterPeerConnection::mapToEncoding(const EncodableMap& params) { encoding->set_active(true); encoding->set_scale_resolution_down_by(1.0); + encoding->set_bitrate_priority(1.0); + encoding->set_network_priority(libwebrtc::RTCPriority::kLow); EncodableValue value = findEncodableValue(params, "active"); if (!value.IsNull()) { @@ -551,6 +596,18 @@ FlutterPeerConnection::mapToEncoding(const EncodableMap& params) { encoding->set_scalability_mode(GetValue(value)); } + value = findEncodableValue(params, "priority"); + if (!value.IsNull()) { + encoding->set_bitrate_priority( + stringToBitratePriority(GetValue(value))); + } + + value = findEncodableValue(params, "networkPriority"); + if (!value.IsNull()) { + encoding->set_network_priority( + stringToRTCPriority(GetValue(value))); + } + return encoding; } @@ -571,15 +628,16 @@ void FlutterPeerConnection::AddTransceiver( std::unique_ptr result) { std::shared_ptr result_ptr(result.release()); - RTCMediaTrack* track = base_->MediaTrackForId(trackId); + scoped_refptr track = base_->MediaTrackForId(trackId); RTCMediaType type = stringToMediaType(mediaType); if (0 < transceiverInit.size()) { auto transceiver = - track != nullptr ? pc->AddTransceiver( - track, mapToRtpTransceiverInit(transceiverInit)) - : pc->AddTransceiver( - type, mapToRtpTransceiverInit(transceiverInit)); + track != nullptr + ? pc->AddTransceiver(track.get(), + mapToRtpTransceiverInit(transceiverInit)) + : pc->AddTransceiver(type, + mapToRtpTransceiverInit(transceiverInit)); if (nullptr != transceiver.get()) { result_ptr->Success(EncodableValue(transceiverToMap(transceiver))); return; @@ -587,8 +645,8 @@ void FlutterPeerConnection::AddTransceiver( result_ptr->Error("AddTransceiver(track | mediaType, init)", "AddTransceiver error"); } else { - auto transceiver = - track != nullptr ? pc->AddTransceiver(track) : pc->AddTransceiver(type); + auto transceiver = track != nullptr ? pc->AddTransceiver(track.get()) + : pc->AddTransceiver(type); if (nullptr != transceiver.get()) { result_ptr->Success(EncodableValue(transceiverToMap(transceiver))); return; @@ -712,6 +770,16 @@ scoped_refptr FlutterPeerConnection::updateRtpParameters( if (!value.IsNull()) { param->set_scalability_mode(GetValue(value)); } + value = findEncodableValue(map, "priority"); + if (!value.IsNull()) { + param->set_bitrate_priority( + stringToBitratePriority(GetValue(value))); + } + value = findEncodableValue(map, "networkPriority"); + if (!value.IsNull()) { + param->set_network_priority( + stringToRTCPriority(GetValue(value))); + } encoding++; } } @@ -802,10 +870,8 @@ void FlutterPeerConnection::SetConfiguration( void FlutterPeerConnection::CaptureFrame( RTCVideoTrack* track, std::string path, std::unique_ptr result) { - // FlutterFrameCapturer capturer(track, path); - // capturer.CaptureFrame(std::move(result)); - std::shared_ptr result_ptr(result.release()); - result_ptr->Success(); + FlutterFrameCapturer capturer(track, path); + capturer.CaptureFrame(std::move(result)); } scoped_refptr FlutterPeerConnection::getRtpTransceiverById( @@ -903,9 +969,6 @@ EncodableMap statsToMap(const scoped_refptr& stats) { auto members = stats->Members(); for (int i = 0; i < members.size(); i++) { auto member = members[i]; - if (!member->IsDefined()) { - continue; - } switch (member->GetType()) { case RTCStatsMember::Type::kBool: values[EncodableValue(member->GetName().std_string())] = @@ -1081,9 +1144,10 @@ void FlutterPeerConnection::RemoveTrack( FlutterPeerConnectionObserver::FlutterPeerConnectionObserver( FlutterWebRTCBase* base, scoped_refptr peerconnection, - BinaryMessenger* messenger, const std::string& channel_name, - std::string& peerConnectionId) - : event_channel_(EventChannelProxy::Create(messenger, channel_name)), + BinaryMessenger* messenger, TaskRunner* task_runner, + const std::string& channel_name, std::string& peerConnectionId) + : event_channel_( + EventChannelProxy::Create(messenger, task_runner, channel_name)), peerconnection_(peerconnection), base_(base), id_(peerConnectionId) { @@ -1287,7 +1351,7 @@ void FlutterPeerConnectionObserver::OnDataChannel( std::unique_ptr observer( new FlutterRTCDataChannelObserver(data_channel, base_->messenger_, - event_channel)); + base_->task_runner_, event_channel)); base_->lock(); base_->data_channel_observers_[channel_uuid] = std::move(observer); diff --git a/packages/flutter_webrtc/tizen/src/flutter_utf8_sanitize.cc b/packages/flutter_webrtc/tizen/src/flutter_utf8_sanitize.cc new file mode 100644 index 000000000..b3725bacb --- /dev/null +++ b/packages/flutter_webrtc/tizen/src/flutter_utf8_sanitize.cc @@ -0,0 +1,106 @@ +#include "flutter_utf8_sanitize.h" + +#include + +namespace flutter_webrtc_plugin { + +// Replace invalid UTF-8 sequences with U+FFFD (EF BF BD). +std::string SanitizeUtf8ForFlutter(const std::string& input) { + std::string out; + out.reserve(input.size()); + const unsigned char* s = reinterpret_cast(input.data()); + const size_t len = input.size(); + size_t i = 0; + + while (i < len) { + const unsigned char c = s[i]; + if (c < 0x80) { + out.push_back(static_cast(c)); + ++i; + continue; + } + if ((c & 0xE0) == 0xC0) { + if (i + 1 >= len) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + const unsigned char c1 = s[i + 1]; + if ((c1 & 0xC0) != 0x80) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + const uint32_t cp = (static_cast(c & 0x1F) << 6) | (c1 & 0x3F); + if (cp < 0x80 || cp > 0x7FF) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + out.push_back(static_cast(c)); + out.push_back(static_cast(c1)); + i += 2; + continue; + } + if ((c & 0xF0) == 0xE0) { + if (i + 2 >= len) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + const unsigned char c1 = s[i + 1]; + const unsigned char c2 = s[i + 2]; + if ((c1 & 0xC0) != 0x80 || (c2 & 0xC0) != 0x80) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + const uint32_t cp = (static_cast(c & 0x0F) << 12) | + (static_cast(c1 & 0x3F) << 6) | (c2 & 0x3F); + if (cp < 0x800 || cp > 0xFFFF || (cp >= 0xD800 && cp <= 0xDFFF)) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + out.push_back(static_cast(c)); + out.push_back(static_cast(c1)); + out.push_back(static_cast(c2)); + i += 3; + continue; + } + if ((c & 0xF8) == 0xF0) { + if (i + 3 >= len) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + const unsigned char c1 = s[i + 1]; + const unsigned char c2 = s[i + 2]; + const unsigned char c3 = s[i + 3]; + if ((c1 & 0xC0) != 0x80 || (c2 & 0xC0) != 0x80 || (c3 & 0xC0) != 0x80) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + const uint32_t cp = (static_cast(c & 0x07) << 18) | + (static_cast(c1 & 0x3F) << 12) | + (static_cast(c2 & 0x3F) << 6) | (c3 & 0x3F); + if (cp < 0x10000 || cp > 0x10FFFF) { + out += "\xEF\xBF\xBD"; + ++i; + continue; + } + out.push_back(static_cast(c)); + out.push_back(static_cast(c1)); + out.push_back(static_cast(c2)); + out.push_back(static_cast(c3)); + i += 4; + continue; + } + out += "\xEF\xBF\xBD"; + ++i; + } + return out; +} + +} // namespace flutter_webrtc_plugin diff --git a/packages/flutter_webrtc/tizen/src/flutter_video_renderer.cc b/packages/flutter_webrtc/tizen/src/flutter_video_renderer.cc index 11e05b84a..7679764f9 100644 --- a/packages/flutter_webrtc/tizen/src/flutter_video_renderer.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_video_renderer.cc @@ -6,13 +6,15 @@ FlutterVideoRenderer::~FlutterVideoRenderer() {} void FlutterVideoRenderer::initialize( TextureRegistrar* registrar, BinaryMessenger* messenger, - std::unique_ptr texture, int64_t trxture_id) { + TaskRunner* task_runner, std::unique_ptr texture, + int64_t trxture_id) { registrar_ = registrar; texture_ = std::move(texture); texture_id_ = trxture_id; std::string channel_name = "FlutterWebRTC/Texture" + std::to_string(texture_id_); - event_channel_ = EventChannelProxy::Create(messenger, channel_name); + event_channel_ = + EventChannelProxy::Create(messenger, task_runner, channel_name); } const FlutterDesktopPixelBuffer* FlutterVideoRenderer::CopyPixelBuffer( @@ -116,7 +118,7 @@ void FlutterVideoRendererManager::CreateVideoRendererTexture( })); auto texture_id = base_->textures_->RegisterTexture(textureVariant.get()); - texture->initialize(base_->textures_, base_->messenger_, + texture->initialize(base_->textures_, base_->messenger_, base_->task_runner_, std::move(textureVariant), texture_id); renderers_[texture_id] = texture; EncodableMap params; diff --git a/packages/flutter_webrtc/tizen/src/flutter_webrtc.cc b/packages/flutter_webrtc/tizen/src/flutter_webrtc.cc index f24d9dc7a..d42bf912c 100644 --- a/packages/flutter_webrtc/tizen/src/flutter_webrtc.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_webrtc.cc @@ -1,17 +1,21 @@ #include "flutter_webrtc.h" +#include "flutter_data_channel.h" #include "log.h" namespace flutter_webrtc_plugin { +static EventChannelProxy* eventChannelProxy = nullptr; + FlutterWebRTC::FlutterWebRTC(FlutterWebRTCPlugin* plugin) - : FlutterWebRTCBase::FlutterWebRTCBase(plugin->messenger(), - plugin->textures()), + : FlutterWebRTCBase::FlutterWebRTCBase( + plugin->messenger(), plugin->textures(), plugin->task_runner()), FlutterVideoRendererManager::FlutterVideoRendererManager(this), FlutterMediaStream::FlutterMediaStream(this), FlutterPeerConnection::FlutterPeerConnection(this), FlutterDataChannel::FlutterDataChannel(this), - FlutterFrameCryptor::FlutterFrameCryptor(this) {} + FlutterFrameCryptor::FlutterFrameCryptor(this), + FlutterDataPacketCryptor::FlutterDataPacketCryptor(this) {} FlutterWebRTC::~FlutterWebRTC() {} @@ -22,6 +26,11 @@ void FlutterWebRTC::HandleMethodCall( const EncodableMap params = GetValue(*method_call.arguments()); const EncodableMap options = findMap(params, "options"); + std::string severityStr = findString(options, "logSeverity"); + if (severityStr.empty() == false) { + RTCLoggingSeverity severity = str2LogSeverity(severityStr); + initLoggerCallback(severity); + } result->Success(); } else if (method_call.method_name().compare("createPeerConnection") == 0) { if (!method_call.arguments()) { @@ -273,11 +282,10 @@ void FlutterWebRTC::HandleMethodCall( SdpParseError error; std::string candidate = findString(constraints, "candidate"); if (candidate.empty()) { - LOG_DEBUG("addCandidate, add end-of-candidates"); + // received the end-of-candidates result->Success(); return; } - int sdpMLineIndex = findInt(constraints, "sdpMLineIndex"); scoped_refptr rtc_candidate = RTCIceCandidate::Create( candidate.c_str(), findString(constraints, "sdpMid").c_str(), @@ -349,6 +357,30 @@ void FlutterWebRTC::HandleMethodCall( return; } DataChannelSend(data_channel, type, data, std::move(result)); + } else if (method_call.method_name().compare( + "dataChannelGetBufferedAmount") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = + GetValue(*method_call.arguments()); + const std::string peerConnectionId = findString(params, "peerConnectionId"); + RTCPeerConnection* pc = PeerConnectionForId(peerConnectionId); + if (pc == nullptr) { + result->Error("dataChannelGetBufferedAmountFailed", + "dataChannelGetBufferedAmount() peerConnection is null"); + return; + } + + const std::string dataChannelId = findString(params, "dataChannelId"); + RTCDataChannel* data_channel = DataChannelForId(dataChannelId); + if (data_channel == nullptr) { + result->Error("dataChannelGetBufferedAmountFailed", + "dataChannelGetBufferedAmount() data_channel is null"); + return; + } + DataChannelGetBufferedAmount(data_channel, std::move(result)); } else if (method_call.method_name().compare("dataChannelClose") == 0) { if (!method_call.arguments()) { result->Error("Bad Arguments", "Null constraints arguments received"); @@ -391,7 +423,7 @@ void FlutterWebRTC::HandleMethodCall( GetValue(*method_call.arguments()); const std::string track_id = findString(params, "trackId"); const EncodableValue enable = findEncodableValue(params, "enabled"); - RTCMediaTrack* track = MediaTrackForId(track_id); + scoped_refptr track = MediaTrackForId(track_id); if (track != nullptr) { track->set_enabled(GetValue(enable)); } @@ -486,6 +518,48 @@ void FlutterWebRTC::HandleMethodCall( const std::string track_id = findString(params, "trackId"); MediaStreamTrackSwitchCamera(track_id, std::move(result)); } else if (method_call.method_name().compare("setVolume") == 0) { + auto args = method_call.arguments(); + if (!args) { + result->Error("Bad Arguments", "setVolume() Null arguments received"); + return; + } + + const EncodableMap params = GetValue(*args); + const std::string trackId = findString(params, "trackId"); + const std::optional volume = maybeFindDouble(params, "volume"); + + if (trackId.empty()) { + result->Error("Bad Arguments", "setVolume() Empty track provided"); + return; + } + + if (!volume.has_value()) { + result->Error("Bad Arguments", "setVolume() No volume provided"); + return; + } + + if (volume.value() < 0) { + result->Error("Bad Arguments", "setVolume() Volume must be positive"); + return; + } + + scoped_refptr 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(track.get()); + audioTrack->SetVolume(volume.value()); + + result->Success(); } else if (method_call.method_name().compare("getLocalDescription") == 0) { if (!method_call.arguments()) { result->Error("Bad Arguments", "Null constraints arguments received"); @@ -721,7 +795,7 @@ void FlutterWebRTC::HandleMethodCall( } const std::string trackId = findString(params, "trackId"); - RTCMediaTrack* track = MediaTrackForId(trackId); + scoped_refptr track = MediaTrackForId(trackId); const std::string rtpSenderId = findString(params, "rtpSenderId"); if (rtpSenderId.empty()) { @@ -729,7 +803,7 @@ void FlutterWebRTC::HandleMethodCall( "rtpSenderSetTrack() rtpSenderId is null or empty"); return; } - RtpSenderSetTrack(pc, track, rtpSenderId, std::move(result)); + RtpSenderSetTrack(pc, track.get(), rtpSenderId, std::move(result)); } else if (method_call.method_name().compare("rtpSenderSetStreams") == 0) { if (!method_call.arguments()) { result->Error("Bad Arguments", "Null constraints arguments received"); @@ -781,7 +855,7 @@ void FlutterWebRTC::HandleMethodCall( } const std::string trackId = findString(params, "trackId"); - RTCMediaTrack* track = MediaTrackForId(trackId); + scoped_refptr track = MediaTrackForId(trackId); const std::string rtpSenderId = findString(params, "rtpSenderId"); if (rtpSenderId.empty()) { @@ -789,7 +863,7 @@ void FlutterWebRTC::HandleMethodCall( "rtpSenderReplaceTrack() rtpSenderId is null or empty"); return; } - RtpSenderReplaceTrack(pc, track, rtpSenderId, std::move(result)); + RtpSenderReplaceTrack(pc, track.get(), rtpSenderId, std::move(result)); } else if (method_call.method_name().compare("rtpSenderSetParameters") == 0) { if (!method_call.arguments()) { result->Error("Bad Arguments", "Null constraints arguments received"); @@ -943,8 +1017,8 @@ void FlutterWebRTC::HandleMethodCall( } const std::string trackId = findString(params, "trackId"); - RTCMediaTrack* track = MediaTrackForId(trackId); - if (nullptr == track) { + scoped_refptr track = MediaTrackForId(trackId); + if (track == nullptr) { result->Error("captureFrame", "captureFrame() track is null"); return; } @@ -953,7 +1027,7 @@ void FlutterWebRTC::HandleMethodCall( result->Error("captureFrame", "captureFrame() track not is video track"); return; } - CaptureFrame(reinterpret_cast(track), path, + CaptureFrame(reinterpret_cast(track.get()), path, std::move(result)); } else if (method_call.method_name().compare("createLocalMediaStream") == 0) { @@ -1197,11 +1271,53 @@ void FlutterWebRTC::HandleMethodCall( state[EncodableValue("state")] = peerConnectionStateString(pc->peer_connection_state()); result->Success(EncodableValue(state)); - } else if (HandleFrameCryptorMethodCall(method_call, std::move(result))) { - // Do nothing + } else if (method_call.method_name().compare("setLogSeverity") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Bad arguments received"); + return; + } + const EncodableMap params = + GetValue(*method_call.arguments()); + std::string severityStr = findString(params, "severity"); + if (severityStr.empty() == false) { + RTCLoggingSeverity severity = str2LogSeverity(severityStr); + initLoggerCallback(severity); + } } else { - result->NotImplemented(); + if (HandleFrameCryptorMethodCall(method_call, std::move(result), &result)) { + return; + } else { + result->NotImplemented(); + } + } +} + +void FlutterWebRTC::initLoggerCallback(RTCLoggingSeverity severity) { + if (eventChannelProxy == nullptr) { + eventChannelProxy = event_channel(); } + + libwebrtc::LibWebRTCLogging::setLogSink(severity, [](const string& message) { + EncodableMap info; + info[EncodableValue("event")] = "onLogData"; + info[EncodableValue("data")] = message.c_string(); + eventChannelProxy->Success(EncodableValue(info), false); + }); +} + +RTCLoggingSeverity FlutterWebRTC::str2LogSeverity(std::string str) { + if (str == "verbose") + return Verbose; + else if (str == "info") + return Info; + else if (str == "warning") + return Warning; + else if (str == "error") + return Error; + else if (str == "none") + return None; + + return None; } } // namespace flutter_webrtc_plugin diff --git a/packages/flutter_webrtc/tizen/src/flutter_webrtc_base.cc b/packages/flutter_webrtc/tizen/src/flutter_webrtc_base.cc index 32e0436e0..c67c41982 100644 --- a/packages/flutter_webrtc/tizen/src/flutter_webrtc_base.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_webrtc_base.cc @@ -2,19 +2,24 @@ #include "flutter_data_channel.h" #include "flutter_peerconnection.h" +#include "helper.h" namespace flutter_webrtc_plugin { const char* kEventChannelName = "FlutterWebRTC.Event"; FlutterWebRTCBase::FlutterWebRTCBase(BinaryMessenger* messenger, - TextureRegistrar* textures) - : messenger_(messenger), textures_(textures) { + TextureRegistrar* textures, + TaskRunner* task_runner) + : messenger_(messenger), task_runner_(task_runner), textures_(textures) { LibWebRTC::Initialize(); factory_ = LibWebRTC::CreateRTCPeerConnectionFactory(); + factory_->Initialize(); audio_device_ = factory_->GetAudioDevice(); video_device_ = factory_->GetVideoDevice(); - event_channel_ = EventChannelProxy::Create(messenger_, kEventChannelName); + audio_processing_ = factory_->GetAudioProcessing(); + event_channel_ = + EventChannelProxy::Create(messenger_, task_runner_, kEventChannelName); } FlutterWebRTCBase::~FlutterWebRTCBase() { LibWebRTC::Terminate(); } @@ -24,7 +29,7 @@ EventChannelProxy* FlutterWebRTCBase::event_channel() { } std::string FlutterWebRTCBase::GenerateUUID() { - return uuidxx::uuid::Generate().ToString(false); + return libwebrtc::Helper::CreateRandomUuid().std_string(); } RTCPeerConnection* FlutterWebRTCBase::PeerConnectionForId( @@ -41,10 +46,11 @@ void FlutterWebRTCBase::RemovePeerConnectionForId(const std::string& id) { if (it != peerconnections_.end()) peerconnections_.erase(it); } -RTCMediaTrack* FlutterWebRTCBase ::MediaTrackForId(const std::string& id) { +scoped_refptr FlutterWebRTCBase ::MediaTrackForId( + const std::string& id) { auto it = local_tracks_.find(id); - if (it != local_tracks_.end()) return (*it).second.get(); + if (it != local_tracks_.end()) return (*it).second; for (auto kv : peerconnection_observers_) { auto pco = kv.second.get(); @@ -290,6 +296,11 @@ bool FlutterWebRTCBase::ParseRTCConfiguration(const EncodableMap& map, conf.sdp_semantics = SdpSemantics::kUnifiedPlan; } + it = map.find(EncodableValue("enableDscp")); + if (it != map.end() && TypeIs(it->second)) { + conf.enable_dscp = GetValue(it->second); + } + // maxIPv6Networks it = map.find(EncodableValue("maxIPv6Networks")); if (it != map.end()) { @@ -347,4 +358,13 @@ FlutterWebRTCBase::GetRtpReceiverById(RTCPeerConnection* pc, std::string id) { return result; } +libwebrtc::scoped_refptr +FlutterWebRTCBase::GetKeyProviderForId(const std::string& keyProviderId) { + auto it = key_providers_.find(keyProviderId); + if (it != key_providers_.end()) { + return it->second; + } + return nullptr; +} + } // namespace flutter_webrtc_plugin diff --git a/packages/flutter_webrtc/tizen/src/flutter_webrtc_tizen_plugin.cc b/packages/flutter_webrtc/tizen/src/flutter_webrtc_tizen_plugin.cc index f5dc6f921..4b2c23f8c 100644 --- a/packages/flutter_webrtc/tizen/src/flutter_webrtc_tizen_plugin.cc +++ b/packages/flutter_webrtc/tizen/src/flutter_webrtc_tizen_plugin.cc @@ -3,6 +3,8 @@ #include "flutter_common.h" #include "flutter_webrtc.h" #include "log.h" +#include "task_runner.h" +#include "task_runner_tizen.h" const char* kChannelName = "FlutterWebRTC.Method"; @@ -36,13 +38,16 @@ class FlutterWebRtcTizenPlugin : public FlutterWebRTCPlugin { TextureRegistrar* textures() { return textures_; } + TaskRunner* task_runner() { return task_runner_.get(); } + private: // Creates a plugin that communicates on the given channel. FlutterWebRtcTizenPlugin(flutter::PluginRegistrar* registrar, std::unique_ptr channel) : channel_(std::move(channel)), messenger_(registrar->messenger()), - textures_(registrar->texture_registrar()) { + textures_(registrar->texture_registrar()), + task_runner_(std::make_unique()) { webrtc_ = std::make_unique(this); } @@ -60,6 +65,7 @@ class FlutterWebRtcTizenPlugin : public FlutterWebRTCPlugin { std::unique_ptr webrtc_; BinaryMessenger* messenger_; TextureRegistrar* textures_; + std::unique_ptr task_runner_; }; } // namespace flutter_webrtc_plugin diff --git a/packages/flutter_webrtc/tizen/src/task_runner_tizen.cc b/packages/flutter_webrtc/tizen/src/task_runner_tizen.cc new file mode 100644 index 000000000..9e56ec35c --- /dev/null +++ b/packages/flutter_webrtc/tizen/src/task_runner_tizen.cc @@ -0,0 +1,25 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "task_runner_tizen.h" + +TaskRunnerTizen::TaskRunnerTizen() = default; + +TaskRunnerTizen::~TaskRunnerTizen() = default; + +void TaskRunnerTizen::EnqueueTask(TaskClosure task) { + std::lock_guard lock(tasks_mutex_); + tasks_.push(std::move(task)); + ecore_main_loop_thread_safe_call_async(RunTask, this); +} + +void TaskRunnerTizen::RunTask(void* data) { + TaskRunnerTizen* runner = static_cast(data); + std::lock_guard lock(runner->tasks_mutex_); + while (!runner->tasks_.empty()) { + TaskClosure task = std::move(runner->tasks_.front()); + runner->tasks_.pop(); + task(); + } +} diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/base/fixed_size_function.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/base/fixed_size_function.h index 1070b4523..9646d4541 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/base/fixed_size_function.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/base/fixed_size_function.h @@ -7,6 +7,7 @@ #ifndef FIXED_SIZE_FUNCTION_HPP_INCLUDED #define FIXED_SIZE_FUNCTION_HPP_INCLUDED +#include #include #include #include diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/base/portable.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/base/portable.h index b403af9cd..6f4238073 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/base/portable.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/base/portable.h @@ -15,6 +15,7 @@ #include #include #include +#include #include /** diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_frame.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_frame.h index 3f276a167..7774f0c78 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_frame.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_frame.h @@ -1,17 +1,17 @@ -#ifndef AUDIO_FRAME_HXX -#define AUDIO_FRAME_HXX +#ifndef LIB_WEBRTC_RTC_AUDIO_FRAME_HXX +#define LIB_WEBRTC_RTC_AUDIO_FRAME_HXX -#include "media_manager_types.h" +#include "rtc_types.h" -namespace b2bua { +namespace libwebrtc { -class AudioFrame { +class AudioFrame : public RefCountInterface { public: /** * @brief Creates a new instance of AudioFrame. * @return AudioFrame*: a pointer to the newly created AudioFrame. */ - MEDIA_MANAGER_API static AudioFrame* Create(); + LIB_WEBRTC_API static AudioFrame* Create(); /** * @brief Creates a new instance of AudioFrame with specified parameters. @@ -23,16 +23,11 @@ class AudioFrame { * @param num_channels: the number of audio channels. * @return AudioFrame*: a pointer to the newly created AudioFrame. */ - MEDIA_MANAGER_API static AudioFrame* Create(int id, uint32_t timestamp, - const int16_t* data, - size_t samples_per_channel, - int sample_rate_hz, - size_t num_channels = 1); - - /** - * @brief Releases the memory of this AudioFrame. - */ - virtual void Release() = 0; + LIB_WEBRTC_API static AudioFrame* Create(int id, uint32_t timestamp, + const int16_t* data, + size_t samples_per_channel, + int sample_rate_hz, + size_t num_channels = 1); public: /** @@ -103,6 +98,6 @@ class AudioFrame { virtual int id() = 0; }; -}; // namespace b2bua +}; // namespace libwebrtc -#endif +#endif // LIB_WEBRTC_RTC_AUDIO_FRAME_HXX diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_processing.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_processing.h new file mode 100644 index 000000000..908a16a38 --- /dev/null +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_processing.h @@ -0,0 +1,35 @@ +#ifndef LIB_WEBRTC_RTC_AUDIO_PROCESSING_HXX +#define LIB_WEBRTC_RTC_AUDIO_PROCESSING_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCAudioProcessing : public RefCountInterface { + public: + class CustomProcessing { + public: + virtual void Initialize(int sample_rate_hz, int num_channels) = 0; + + virtual void Process(int num_bands, int num_frames, int buffer_size, + float* buffer) = 0; + + virtual void Reset(int new_rate) = 0; + + virtual void Release() = 0; + + protected: + virtual ~CustomProcessing() {} + }; + + public: + virtual void SetCapturePostProcessing( + CustomProcessing* capture_post_processing) = 0; + + virtual void SetRenderPreProcessing( + CustomProcessing* render_pre_processing) = 0; +}; + +} // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_AUDIO_PROCESSING_HXX \ No newline at end of file diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_source.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_source.h index 43e39fd80..e2f98fca0 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_source.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_source.h @@ -13,6 +13,16 @@ namespace libwebrtc { * processing and transmission mechanisms. */ class RTCAudioSource : public RefCountInterface { + public: + enum SourceType { kMicrophone, kCustom }; + + public: + virtual void CaptureFrame(const void* audio_data, int bits_per_sample, + int sample_rate, size_t number_of_channels, + size_t number_of_frames) = 0; + + virtual SourceType GetSourceType() const = 0; + protected: /** * The destructor for the RTCAudioSource class. diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_track.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_track.h index c64e4bc4a..82459005d 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_track.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_audio_track.h @@ -17,6 +17,10 @@ class RTCAudioTrack : public RTCMediaTrack { // volume in [0-10] virtual void SetVolume(double volume) = 0; + virtual void AddSink(AudioTrackSink* sink) = 0; + + virtual void RemoveSink(AudioTrackSink* sink) = 0; + protected: /** * The destructor for the RTCAudioTrack class. diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_data_channel.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_data_channel.h index 183d5da6d..e1351959f 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_data_channel.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_data_channel.h @@ -103,6 +103,13 @@ class RTCDataChannel : public RefCountInterface { */ virtual int id() const = 0; + /** + * Returns the amount of data buffered in the data channel. + * + * @return uint64_t + */ + virtual uint64_t buffered_amount() const = 0; + /** * Returns the state of the data channel. */ diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_data_packet_cryptor.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_data_packet_cryptor.h new file mode 100644 index 000000000..96db50691 --- /dev/null +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_data_packet_cryptor.h @@ -0,0 +1,38 @@ +#ifndef LIB_RTC_DATA_PACKET_CRYPTOR_H_ +#define LIB_RTC_DATA_PACKET_CRYPTOR_H_ + +#include "base/refcount.h" +#include "rtc_frame_cryptor.h" +#include "rtc_types.h" + +namespace libwebrtc { + +class EncryptedPacket : public RefCountInterface { + public: + LIB_WEBRTC_API static scoped_refptr Create( + vector data, vector iv, uint8_t key_index); + virtual vector data() = 0; + virtual vector iv() = 0; + virtual uint8_t key_index() = 0; +}; + +class RTCDataPacketCryptor : public RefCountInterface { + public: + LIB_WEBRTC_API static scoped_refptr Create( + scoped_refptr key_provider, FrameCryptorAlgorithm algorithm); + + virtual scoped_refptr encrypt(string participant_id, + int key_index, + vector data) = 0; + + virtual vector decrypt( + string participant_id, int key_index, + scoped_refptr encrypted_packet) = 0; + + protected: + virtual ~RTCDataPacketCryptor() {} +}; + +} // namespace libwebrtc + +#endif // LIB_RTC_DATA_PACKET_CRYPTOR_H_ \ No newline at end of file diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_desktop_device.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_desktop_device.h index e3e4c6fab..5904b5745 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_desktop_device.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_desktop_device.h @@ -1,6 +1,9 @@ #ifndef LIB_WEBRTC_RTC_DESKTOP_DEVICE_HXX #define LIB_WEBRTC_RTC_DESKTOP_DEVICE_HXX +#include +#include + #include "rtc_types.h" namespace libwebrtc { @@ -12,7 +15,7 @@ class RTCDesktopMediaList; class RTCDesktopDevice : public RefCountInterface { public: virtual scoped_refptr CreateDesktopCapturer( - scoped_refptr source) = 0; + scoped_refptr source, bool showCursor = true) = 0; virtual scoped_refptr GetDesktopMediaList( DesktopType type) = 0; diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_frame_cryptor.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_frame_cryptor.h index 7e0436cdd..5c7ff4762 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_frame_cryptor.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_frame_cryptor.h @@ -9,27 +9,46 @@ namespace libwebrtc { -enum class Algorithm { +enum class FrameCryptorAlgorithm { kAesGcm = 0, kAesCbc, }; +enum class KeyDerivationAlgorithm { + kPBKDF2 = 0, + kHKDF, +}; + +#define DEFAULT_KEYRING_SIZE 16 +#define MAX_KEYRING_SIZE 255 + struct KeyProviderOptions { bool shared_key; vector ratchet_salt; vector uncrypted_magic_bytes; int ratchet_window_size; int failure_tolerance; + // The size of the key ring. between 1 and 255. + int key_ring_size; + bool discard_frame_when_cryptor_not_ready; + KeyDerivationAlgorithm key_derivation_algorithm; KeyProviderOptions() : shared_key(false), ratchet_salt(vector()), ratchet_window_size(0), - failure_tolerance(-1) {} + failure_tolerance(-1), + key_ring_size(DEFAULT_KEYRING_SIZE), + discard_frame_when_cryptor_not_ready(false), + key_derivation_algorithm(KeyDerivationAlgorithm::kPBKDF2) {} KeyProviderOptions(KeyProviderOptions& copy) : shared_key(copy.shared_key), ratchet_salt(copy.ratchet_salt), ratchet_window_size(copy.ratchet_window_size), - failure_tolerance(copy.failure_tolerance) {} + failure_tolerance(copy.failure_tolerance), + key_ring_size(copy.key_ring_size), + discard_frame_when_cryptor_not_ready( + copy.discard_frame_when_cryptor_not_ready), + key_derivation_algorithm(copy.key_derivation_algorithm) {} }; /// Shared secret key for frame encryption. @@ -113,7 +132,7 @@ class FrameCryptorFactory { frameCryptorFromRtpSender(scoped_refptr factory, const string participant_id, scoped_refptr sender, - Algorithm algorithm, + FrameCryptorAlgorithm algorithm, scoped_refptr key_provider); /// Create a frame cyrptor for [RTCRtpReceiver]. @@ -121,7 +140,7 @@ class FrameCryptorFactory { frameCryptorFromRtpReceiver(scoped_refptr factory, const string participant_id, scoped_refptr receiver, - Algorithm algorithm, + FrameCryptorAlgorithm algorithm, scoped_refptr key_provider); }; diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_ice_transport.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_ice_transport.h index b6c1ee5a6..698f56cbb 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_ice_transport.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_ice_transport.h @@ -21,7 +21,8 @@ #include "rtc_base/ref_count.h" namespace libwebrtc { -class IceTransport : public rtc::RefCountInterface { + +class IceTransport : public RefCountInterface { public: virtual IceTransport* internal() = 0; }; @@ -34,8 +35,8 @@ class IceTransportInit final { IceTransportInit& operator=(const IceTransportInit&) = delete; IceTransportInit& operator=(IceTransportInit&&) = default; - cricket::PortAllocator* port_allocator() { return port_allocator_; } - void set_port_allocator(cricket::PortAllocator* port_allocator) { + webrtc::PortAllocator* port_allocator() { return port_allocator_; } + void set_port_allocator(webrtc::PortAllocator* port_allocator) { port_allocator_ = port_allocator; } diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_logging.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_logging.h new file mode 100644 index 000000000..b097afa7e --- /dev/null +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_logging.h @@ -0,0 +1,28 @@ +#ifndef LIB_WEBRTC_RTC_LOGGING_HXX +#define LIB_WEBRTC_RTC_LOGGING_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +enum RTCLoggingSeverity { + Verbose, + Info, + Warning, + Error, + None, +}; + +typedef void (*RTCCallbackLoggerMessageHandler)(const string& message); + +class LibWebRTCLogging { + public: + LIB_WEBRTC_API static void setMinDebugLogLevel(RTCLoggingSeverity severity); + LIB_WEBRTC_API static void setLogSink( + RTCLoggingSeverity severity, + RTCCallbackLoggerMessageHandler callbackHandler); + LIB_WEBRTC_API static void removeLogSink(); +}; +} // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_LOGGING_HXX diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_media_track.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_media_track.h index ff5a2f743..ffaef5cad 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_media_track.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_media_track.h @@ -5,6 +5,16 @@ namespace libwebrtc { +class AudioTrackSink { + public: + virtual void OnData(const void* audio_data, int bits_per_sample, + int sample_rate, size_t number_of_channels, + size_t number_of_frames) = 0; + + protected: + virtual ~AudioTrackSink() {} +}; + /*Media Track interface*/ class RTCMediaTrack : public RefCountInterface { public: diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_mediaconstraints.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_mediaconstraints.h index 93c729fdf..49673e517 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_mediaconstraints.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_mediaconstraints.h @@ -51,8 +51,8 @@ class RTCMediaConstraints : public RefCountInterface { LIB_WEBRTC_API static const char* kEnableVideoSuspendBelowMinBitrate; // googSuspendBelowMinBitrate // Constraint to enable combined audio+video bandwidth estimation. - LIB_WEBRTC_API static const char* - kCombinedAudioVideoBwe; // googCombinedAudioVideoBwe + // LIB_WEBRTC_API static const char* + // kCombinedAudioVideoBwe; // googCombinedAudioVideoBwe LIB_WEBRTC_API static const char* kScreencastMinBitrate; // googScreencastMinBitrate LIB_WEBRTC_API static const char* diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_peerconnection_factory.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_peerconnection_factory.h index cb024672c..f520f362c 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_peerconnection_factory.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_peerconnection_factory.h @@ -16,6 +16,7 @@ namespace libwebrtc { class RTCPeerConnection; class RTCAudioDevice; +class RTCAudioProcessing; class RTCVideoDevice; class RTCRtpCapabilities; @@ -33,12 +34,17 @@ class RTCPeerConnectionFactory : public RefCountInterface { virtual scoped_refptr GetAudioDevice() = 0; + virtual scoped_refptr GetAudioProcessing() = 0; + virtual scoped_refptr GetVideoDevice() = 0; #ifdef RTC_DESKTOP_DEVICE virtual scoped_refptr GetDesktopDevice() = 0; #endif virtual scoped_refptr CreateAudioSource( - const string audio_source_label) = 0; + const string audio_source_label, + RTCAudioSource::SourceType source_type = + RTCAudioSource::SourceType::kMicrophone, + RTCAudioOptions options = RTCAudioOptions()) = 0; virtual scoped_refptr CreateVideoSource( scoped_refptr capturer, const string video_source_label, diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_rtp_parameters.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_rtp_parameters.h index 3ef87155d..3b337842e 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_rtp_parameters.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_rtp_parameters.h @@ -45,6 +45,7 @@ enum class RTCDegradationPreference { MAINTAIN_FRAMERATE, MAINTAIN_RESOLUTION, BALANCED, + MAINTAIN_FRAMERATE_AND_RESOLUTION, }; class RTCRtcpFeedback : public RefCountInterface { diff --git a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_types.h b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_types.h index 017386d07..d3123a281 100644 --- a/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_types.h +++ b/packages/flutter_webrtc/tizen/third_party/libwebrtc/include/rtc_types.h @@ -91,6 +91,7 @@ struct RTCConfiguration { int max_ipv6_networks = 5; bool disable_link_local_networks = false; int screencast_min_bitrate = -1; + bool enable_dscp = false; // private bool use_rtp_mux = true; @@ -108,6 +109,18 @@ struct SdpParseError { enum DesktopType { kScreen, kWindow }; +struct RTCAudioOptions { + RTCAudioOptions() {} + + bool echo_cancellation = true; + + bool auto_gain_control = true; + + bool noise_suppression = true; + + bool highpass_filter = false; +}; + } // namespace libwebrtc #endif // LIB_WEBRTC_RTC_TYPES_HXX diff --git a/packages/flutter_webrtc/tizen/third_party/svpng/LICENSE b/packages/flutter_webrtc/tizen/third_party/svpng/LICENSE new file mode 100755 index 000000000..c4063034b --- /dev/null +++ b/packages/flutter_webrtc/tizen/third_party/svpng/LICENSE @@ -0,0 +1,26 @@ +Copyright (C) 2017 Milo Yip. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of pngout nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/flutter_webrtc/tizen/third_party/svpng/svpng.hpp b/packages/flutter_webrtc/tizen/third_party/svpng/svpng.hpp new file mode 100755 index 000000000..aa2332429 --- /dev/null +++ b/packages/flutter_webrtc/tizen/third_party/svpng/svpng.hpp @@ -0,0 +1,110 @@ +/* +Copyright (C) 2017 Milo Yip. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of pngout nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*! \file + \brief svpng() is a minimalistic C function for saving RGB/RGBA image into uncompressed PNG. + \author Milo Yip + \version 0.1.1 + \copyright MIT license + \sa https://github.com/miloyip/svpng +*/ + +#ifndef SVPNG_INC_ +#define SVPNG_INC_ + +/*! \def SVPNG_LINKAGE + \brief User customizable linkage for svpng() function. + By default this macro is empty. + User may define this macro as static for static linkage, + and/or inline in C99/C++, etc. +*/ +#ifndef SVPNG_LINKAGE +#define SVPNG_LINKAGE +#endif + +/*! \def SVPNG_OUTPUT + \brief User customizable output stream. + By default, it uses C file descriptor and fputc() to output bytes. + In C++, for example, user may use std::ostream or std::vector instead. +*/ +#ifndef SVPNG_OUTPUT +#include +#define SVPNG_OUTPUT FILE* fp +#endif + +/*! \def SVPNG_PUT + \brief Write a byte +*/ +#ifndef SVPNG_PUT +#define SVPNG_PUT(u) fputc(u, fp) +#endif + + +/*! + \brief Save a RGB/RGBA image in PNG format. + \param SVPNG_OUTPUT Output stream (by default using file descriptor). + \param w Width of the image. (<16383) + \param h Height of the image. + \param img Image pixel data in 24-bit RGB or 32-bit RGBA format. + \param alpha Whether the image contains alpha channel. +*/ +SVPNG_LINKAGE void svpng(SVPNG_OUTPUT, unsigned w, unsigned h, const unsigned char* img, int alpha) { + static const unsigned t[] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + /* CRC32 Table */ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + unsigned a = 1, b = 0, c, p = w * (alpha ? 4 : 3) + 1, x, y, i; /* ADLER-a, ADLER-b, CRC, pitch */ +#define SVPNG_U8A(ua, l) for (i = 0; i < l; i++) SVPNG_PUT((ua)[i]); +#define SVPNG_U32(u) do { SVPNG_PUT((u) >> 24); SVPNG_PUT(((u) >> 16) & 255); SVPNG_PUT(((u) >> 8) & 255); SVPNG_PUT((u) & 255); } while(0) +#define SVPNG_U8C(u) do { SVPNG_PUT(u); c ^= (u); c = (c >> 4) ^ t[c & 15]; c = (c >> 4) ^ t[c & 15]; } while(0) +#define SVPNG_U8AC(ua, l) for (i = 0; i < l; i++) SVPNG_U8C((ua)[i]) +#define SVPNG_U16LC(u) do { SVPNG_U8C((u) & 255); SVPNG_U8C(((u) >> 8) & 255); } while(0) +#define SVPNG_U32C(u) do { SVPNG_U8C((u) >> 24); SVPNG_U8C(((u) >> 16) & 255); SVPNG_U8C(((u) >> 8) & 255); SVPNG_U8C((u) & 255); } while(0) +#define SVPNG_U8ADLER(u) do { SVPNG_U8C(u); a = (a + (u)) % 65521; b = (b + a) % 65521; } while(0) +#define SVPNG_BEGIN(s, l) do { SVPNG_U32(l); c = ~0U; SVPNG_U8AC(s, 4); } while(0) +#define SVPNG_END() SVPNG_U32(~c) + SVPNG_U8A("\x89PNG\r\n\32\n", 8); /* Magic */ + SVPNG_BEGIN("IHDR", 13); /* IHDR chunk { */ + SVPNG_U32C(w); SVPNG_U32C(h); /* Width & Height (8 bytes) */ + SVPNG_U8C(8); SVPNG_U8C(alpha ? 6 : 2); /* Depth=8, Color=True color with/without alpha (2 bytes) */ + SVPNG_U8AC("\0\0\0", 3); /* Compression=Deflate, Filter=No, Interlace=No (3 bytes) */ + SVPNG_END(); /* } */ + SVPNG_BEGIN("IDAT", 2 + h * (5 + p) + 4); /* IDAT chunk { */ + SVPNG_U8AC("\x78\1", 2); /* Deflate block begin (2 bytes) */ + for (y = 0; y < h; y++) { /* Each horizontal line makes a block for simplicity */ + SVPNG_U8C(y == h - 1); /* 1 for the last block, 0 for others (1 byte) */ + SVPNG_U16LC(p); SVPNG_U16LC(~p); /* Size of block in little endian and its 1's complement (4 bytes) */ + SVPNG_U8ADLER(0); /* No filter prefix (1 byte) */ + for (x = 0; x < p - 1; x++, img++) + SVPNG_U8ADLER(*img); /* Image pixel data */ + } + SVPNG_U32C((b << 16) | a); /* Deflate block end with adler (4 bytes) */ + SVPNG_END(); /* } */ + SVPNG_BEGIN("IEND", 0); SVPNG_END(); /* IEND chunk {} */ +} + +#endif /* SVPNG_INC_ */ \ No newline at end of file