diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..3c73f32a33 --- /dev/null +++ b/.clang-format @@ -0,0 +1,12 @@ +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium +# This defaults to 'Auto'. Explicitly set it for a while, so that +# 'vector >' in existing files gets formatted to +# 'vector>'. ('Auto' means that clang-format will only use +# 'int>>' if the file already contains at least one such instance.) +Standard: Cpp11 +SortIncludes: true +--- +Language: ObjC +ColumnLimit: 100 diff --git a/README.md b/README.md index 5e589da7e2..0b3419a76c 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ WebRTC plugin for Flutter Mobile/Desktop/Web | Feature | Android | iOS | [Web](https://flutter.dev/web) | macOS | Windows | Linux | [Fuchsia](https://fuchsia.googlesource.com/) | | :-------------: | :-------------:| :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | -| Audio/Video | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | [WIP] | | -| Data Channel | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | [WIP] | | +| Audio/Video | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | | +| Data Channel | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | | | Screen Capture | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | | | | Unified-Plan | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | | | Simulcast | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | | diff --git a/example/lib/src/loopback_sample.dart b/example/lib/src/loopback_sample.dart index 13f6fb5be1..ef722249d8 100644 --- a/example/lib/src/loopback_sample.dart +++ b/example/lib/src/loopback_sample.dart @@ -89,7 +89,7 @@ class _MyAppState extends State { void _onAddStream(MediaStream stream) { print('New stream: ' + stream.id); - //_remoteRenderer.srcObject = stream; + _remoteRenderer.srcObject = stream; } void _onRemoveStream(MediaStream stream) { @@ -175,7 +175,7 @@ class _MyAppState extends State { _localStream = await navigator.mediaDevices.getUserMedia(mediaConstraints); _localRenderer.srcObject = _localStream; - + await _peerConnection.addStream(_localStream); /* old API await _peerConnection.addStream(_localStream); // Unified-Plan @@ -184,13 +184,13 @@ class _MyAppState extends State { }); */ // or - + /* await _peerConnection.addTransceiver( track: _localStream.getAudioTracks()[0], init: RTCRtpTransceiverInit( direction: TransceiverDirection.SendRecv, streams: [_localStream]), ); - + */ /* // ignore: unused_local_variable var transceiver = await _peerConnection.addTransceiver( @@ -200,6 +200,7 @@ class _MyAppState extends State { ); */ + /* // Unified-Plan Simulcast await _peerConnection.addTransceiver( track: _localStream.getVideoTracks()[0], @@ -227,7 +228,7 @@ class _MyAppState extends State { ), ], )); - /* + await _peerConnection.addTransceiver( kind: RTCRtpMediaType.RTCRtpMediaTypeVideo); await _peerConnection.addTransceiver( diff --git a/lib/src/native/media_stream_impl.dart b/lib/src/native/media_stream_impl.dart index 845f7f2216..6ee278487e 100644 --- a/lib/src/native/media_stream_impl.dart +++ b/lib/src/native/media_stream_impl.dart @@ -21,13 +21,13 @@ class MediaStreamNative extends MediaStream { void setMediaTracks(List audioTracks, List videoTracks) { _audioTracks.clear(); - audioTracks.forEach((track) { + audioTracks?.forEach((track) { _audioTracks.add(MediaStreamTrackNative( track['id'], track['label'], track['kind'], track['enabled'])); }); _videoTracks.clear(); - videoTracks.forEach((track) { + videoTracks?.forEach((track) { _videoTracks.add(MediaStreamTrackNative( track['id'], track['label'], track['kind'], track['enabled'])); }); diff --git a/lib/src/native/rtc_video_view_impl.dart b/lib/src/native/rtc_video_view_impl.dart index 2c486eafa6..095fed2cbd 100644 --- a/lib/src/native/rtc_video_view_impl.dart +++ b/lib/src/native/rtc_video_view_impl.dart @@ -51,13 +51,14 @@ class RTCVideoView extends StatelessWidget { return SizedBox( width: constraints.maxHeight * value.aspectRatio, height: constraints.maxHeight, - child: value.renderVideo ? child : Container(), + child: child, ); }, child: Transform( transform: Matrix4.identity()..rotateY(mirror ? -pi : 0.0), alignment: FractionalOffset.center, - child: videoRenderer.textureId != null + child: videoRenderer.textureId != null && + videoRenderer.srcObject != null ? Texture( textureId: videoRenderer.textureId, filterQuality: filterQuality, diff --git a/macos/WebRTC.framework/Headers b/macos/WebRTC.framework/Headers deleted file mode 120000 index a177d2a6b9..0000000000 --- a/macos/WebRTC.framework/Headers +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Headers \ No newline at end of file diff --git a/macos/WebRTC.framework/Headers b/macos/WebRTC.framework/Headers new file mode 100644 index 0000000000..a177d2a6b9 --- /dev/null +++ b/macos/WebRTC.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/macos/WebRTC.framework/Modules b/macos/WebRTC.framework/Modules deleted file mode 120000 index 5736f3186e..0000000000 --- a/macos/WebRTC.framework/Modules +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Modules \ No newline at end of file diff --git a/macos/WebRTC.framework/Modules b/macos/WebRTC.framework/Modules new file mode 100644 index 0000000000..5736f3186e --- /dev/null +++ b/macos/WebRTC.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/macos/WebRTC.framework/Resources b/macos/WebRTC.framework/Resources deleted file mode 120000 index 953ee36f3b..0000000000 --- a/macos/WebRTC.framework/Resources +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Resources \ No newline at end of file diff --git a/macos/WebRTC.framework/Resources b/macos/WebRTC.framework/Resources new file mode 100644 index 0000000000..953ee36f3b --- /dev/null +++ b/macos/WebRTC.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index e6784e72e5..ecc51d4c9d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,3 +26,5 @@ flutter: pluginClass: FlutterWebRTCPlugin macos: pluginClass: FlutterWebRTCPlugin + windows: + pluginClass: FlutterWebRTCPlugin diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 0000000000..c765fa7864 --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1,4 @@ +flutter/ + +# Visual Studio files +*.user diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt new file mode 100644 index 0000000000..fecd29c6bf --- /dev/null +++ b/windows/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.15) +set(PROJECT_NAME "flutter_webrtc") +project(${PROJECT_NAME} LANGUAGES CXX) + +# This value is used when generating builds using this plugin, so it must +# not be changed +set(PLUGIN_NAME "flutter_webrtc_plugin") + +add_definitions(-DLIB_WEBRTC_API_DLL) + +add_library(${PLUGIN_NAME} SHARED + "flutter_webrtc_plugin.cc" + "src/flutter_data_channel.cc" + "src/flutter_media_stream.cc" + "src/flutter_peerconnection.cc" + "src/flutter_video_renderer.cc" + "src/flutter_webrtc.cc" + "src/flutter_webrtc_base.cc" + "third_party/uuidxx/uuidxx.cc" +) + +include_directories( + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/third_party/uuidxx" + "${CMAKE_CURRENT_SOURCE_DIR}/third_party/uuidxx" + "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libwebrtc/include" +) + +apply_standard_settings(${PLUGIN_NAME}) +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include" +) +target_link_libraries(${PLUGIN_NAME} PRIVATE + flutter + flutter_wrapper_plugin + "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libwebrtc/lib/libwebrtc.dll.lib" +) + +# List of absolute paths to libraries that should be bundled with the plugin +set(flutter_webrtc_bundled_libraries + "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libwebrtc/lib/libwebrtc.dll" + PARENT_SCOPE +) diff --git a/windows/flutter_webrtc_plugin.cc b/windows/flutter_webrtc_plugin.cc new file mode 100644 index 0000000000..ac92b43168 --- /dev/null +++ b/windows/flutter_webrtc_plugin.cc @@ -0,0 +1,72 @@ +#include "flutter_webrtc/flutter_web_r_t_c_plugin.h" + +#include + +#include "flutter_webrtc.h" + +const char *kChannelName = "FlutterWebRTC.Method"; + +namespace flutter_webrtc_plugin { + +// A webrtc plugin for windows/linux. +class FlutterWebRTCPluginImpl : public FlutterWebRTCPlugin { + public: + static void RegisterWithRegistrar(flutter::PluginRegistrar *registrar) { + auto channel = std::make_unique>( + registrar->messenger(), kChannelName, + &flutter::StandardMethodCodec::GetInstance()); + + auto *channel_pointer = channel.get(); + + // Uses new instead of make_unique due to private constructor. + std::unique_ptr plugin( + new FlutterWebRTCPluginImpl(registrar, std::move(channel))); + + channel_pointer->SetMethodCallHandler( + [plugin_pointer = plugin.get()](const auto &call, auto result) { + plugin_pointer->HandleMethodCall(call, std::move(result)); + }); + + registrar->AddPlugin(std::move(plugin)); + } + + virtual ~FlutterWebRTCPluginImpl() {} + + flutter::BinaryMessenger *messenger() { return messenger_; } + + flutter::TextureRegistrar *textures() { return textures_; } + + private: + // Creates a plugin that communicates on the given channel. + FlutterWebRTCPluginImpl( + flutter::PluginRegistrar *registrar, + std::unique_ptr> channel) + : channel_(std::move(channel)), + messenger_(registrar->messenger()), + textures_(registrar->texture_registrar()) { + webrtc_ = std::make_unique(this); + } + + // Called when a method is called on |channel_|; + void HandleMethodCall( + const flutter::MethodCall &method_call, + std::unique_ptr> result) { + // handle method call and forward to webrtc native sdk. + webrtc_->HandleMethodCall(method_call, std::move(result)); + } + + private: + std::unique_ptr> channel_; + std::unique_ptr webrtc_; + flutter::BinaryMessenger *messenger_; + flutter::TextureRegistrar *textures_; +}; + +} // namespace flutter_webrtc_plugin + +void FlutterWebRTCPluginRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar) { + static auto *plugin_registrar = new flutter::PluginRegistrar(registrar); + flutter_webrtc_plugin::FlutterWebRTCPluginImpl::RegisterWithRegistrar( + plugin_registrar); +} diff --git a/windows/include/flutter_data_channel.h b/windows/include/flutter_data_channel.h new file mode 100644 index 0000000000..e6d0d387a1 --- /dev/null +++ b/windows/include/flutter_data_channel.h @@ -0,0 +1,51 @@ +#ifndef FLUTTER_WEBRTC_RTC_DATA_CHANNEL_HXX +#define FLUTTER_WEBRTC_RTC_DATA_CHANNEL_HXX + +#include "flutter_webrtc_base.h" + +namespace flutter_webrtc_plugin { + +class FlutterRTCDataChannelObserver : public RTCDataChannelObserver { + public: + FlutterRTCDataChannelObserver(scoped_refptr data_channel, + BinaryMessenger *messenger, + const std::string &channel_name); + virtual ~FlutterRTCDataChannelObserver(); + + virtual void OnStateChange(RTCDataChannelState state) override; + + virtual void OnMessage(const char *buffer, int length, bool binary) override; + + scoped_refptr data_channel() { return data_channel_; } + + private: + std::unique_ptr> event_channel_; + std::unique_ptr> event_sink_; + scoped_refptr data_channel_; +}; + +class FlutterDataChannel { + public: + FlutterDataChannel(FlutterWebRTCBase *base) : base_(base) {} + + void CreateDataChannel(const std::string &label, + const EncodableMap &dataChannelDict, + RTCPeerConnection *pc, + std::unique_ptr>); + + void DataChannelSend(RTCDataChannel *data_channel, const std::string &type, + const EncodableValue &data, + std::unique_ptr>); + + void DataChannelClose(RTCDataChannel *data_channel, + std::unique_ptr>); + + RTCDataChannel *DataChannelFormId(int id); + + private: + FlutterWebRTCBase *base_; +}; + +} // namespace flutter_webrtc_plugin + +#endif // !FLUTTER_WEBRTC_RTC_DATA_CHANNEL_HXX \ No newline at end of file diff --git a/windows/include/flutter_media_stream.h b/windows/include/flutter_media_stream.h new file mode 100644 index 0000000000..913d30c073 --- /dev/null +++ b/windows/include/flutter_media_stream.h @@ -0,0 +1,50 @@ +#ifndef FLUTTER_WEBRTC_RTC_GET_USERMEDIA_HXX +#define FLUTTER_WEBRTC_RTC_GET_USERMEDIA_HXX + +#include "flutter_webrtc_base.h" + +namespace flutter_webrtc_plugin { + +using namespace flutter; + +class FlutterMediaStream { + public: + FlutterMediaStream(FlutterWebRTCBase *base) : base_(base) {} + + void GetUserMedia(const EncodableMap &constraints, + std::unique_ptr> result); + + void GetUserAudio(const EncodableMap &constraints, + scoped_refptr stream, EncodableMap ¶ms); + + void GetUserVideo(const EncodableMap &constraints, + scoped_refptr stream, EncodableMap ¶ms); + + void GetSources(std::unique_ptr> result); + + void MediaStreamGetTracks( + const std::string &stream_id, + std::unique_ptr> result); + + void MediaStreamDispose(const std::string &stream_id, + std::unique_ptr> result); + + void MediaStreamTrackSetEnable( + const std::string &track_id, + std::unique_ptr> result); + + void MediaStreamTrackSwitchCamera( + const std::string &track_id, + std::unique_ptr> result); + + void MediaStreamTrackDispose( + const std::string &track_id, + std::unique_ptr> result); + + private: + FlutterWebRTCBase *base_; +}; + +} // namespace flutter_webrtc_plugin + +#endif // !FLUTTER_WEBRTC_RTC_GET_USERMEDIA_HXX diff --git a/windows/include/flutter_peerconnection.h b/windows/include/flutter_peerconnection.h new file mode 100644 index 0000000000..0793d1f9a7 --- /dev/null +++ b/windows/include/flutter_peerconnection.h @@ -0,0 +1,89 @@ +#ifndef FLUTTER_WEBRTC_RTC_PEER_CONNECTION_HXX +#define FLUTTER_WEBRTC_RTC_PEER_CONNECTION_HXX + +#include "flutter_webrtc_base.h" + +namespace flutter_webrtc_plugin { + +using namespace flutter; + +class FlutterPeerConnectionObserver : public RTCPeerConnectionObserver { + public: + FlutterPeerConnectionObserver(FlutterWebRTCBase *base, + scoped_refptr peerconnection, + BinaryMessenger *messenger, + const std::string &channel_name); + + virtual void OnSignalingState(RTCSignalingState state) override; + virtual void OnIceGatheringState(RTCIceGatheringState state) override; + virtual void OnIceConnectionState(RTCIceConnectionState state) override; + virtual void OnIceCandidate( + scoped_refptr candidate) override; + virtual void OnAddStream(scoped_refptr stream) override; + virtual void OnRemoveStream(scoped_refptr stream) override; + virtual void OnAddTrack(scoped_refptr stream, + scoped_refptr track) override; + virtual void OnRemoveTrack(scoped_refptr stream, + scoped_refptr track) override; + virtual void OnDataChannel( + scoped_refptr data_channel) override; + virtual void OnRenegotiationNeeded() override; + + scoped_refptr MediaStreamForId( + const std::string &id) { + auto it = remote_streams_.find(id); + if (it != remote_streams_.end()) return (*it).second; + return nullptr; + } + + void RemoveStreamForId(const std::string &id) { + auto it = remote_streams_.find(id); + if (it != remote_streams_.end()) remote_streams_.erase(it); + } + + private: + std::unique_ptr> event_channel_; + std::unique_ptr> event_sink_; + scoped_refptr peerconnection_; + std::map> remote_streams_; + FlutterWebRTCBase *base_; +}; + +class FlutterPeerConnection { + public: + FlutterPeerConnection(FlutterWebRTCBase *base) : base_(base) {} + + void CreateRTCPeerConnection( + const EncodableMap &configuration, const EncodableMap &constraints, + std::unique_ptr> result); + + void RTCPeerConnectionClose( + RTCPeerConnection *pc, const std::string &uuid, + std::unique_ptr> result); + + void CreateOffer(const EncodableMap &constraints, RTCPeerConnection *pc, + std::unique_ptr> result); + + void CreateAnswer(const EncodableMap &constraints, RTCPeerConnection *pc, + std::unique_ptr> result); + + void SetLocalDescription( + RTCSessionDescription *sdp, RTCPeerConnection *pc, + std::unique_ptr> result); + + void SetRemoteDescription( + RTCSessionDescription *sdp, RTCPeerConnection *pc, + std::unique_ptr> result); + + void AddIceCandidate(RTCIceCandidate *candidate, RTCPeerConnection *pc, + std::unique_ptr> result); + + void GetStats(const std::string &track_id, RTCPeerConnection *pc, + std::unique_ptr> result); + + private: + FlutterWebRTCBase *base_; +}; +} // namespace flutter_webrtc_plugin + +#endif // !FLUTTER_WEBRTC_RTC_PEER_CONNECTION_HXX \ No newline at end of file diff --git a/windows/include/flutter_video_renderer.h b/windows/include/flutter_video_renderer.h new file mode 100644 index 0000000000..3d9ede3e18 --- /dev/null +++ b/windows/include/flutter_video_renderer.h @@ -0,0 +1,68 @@ +#ifndef FLUTTER_WEBRTC_RTC_VIDEO_RENDERER_HXX +#define FLUTTER_WEBRTC_RTC_VIDEO_RENDERER_HXX + +#include + +#include "flutter_webrtc_base.h" +#include "rtc_video_frame.h" +#include "rtc_video_renderer.h" + +namespace flutter_webrtc_plugin { + +using namespace libwebrtc; +using namespace flutter; + +class FlutterVideoRenderer: public RTCVideoRenderer> { + public: + FlutterVideoRenderer(TextureRegistrar *registrar, BinaryMessenger *messenger); + + virtual const FlutterDesktopPixelBuffer* CopyPixelBuffer( + size_t width, + size_t height) const; + + virtual void OnFrame(scoped_refptr frame) override; + + void SetVideoTrack(scoped_refptr track); + + int64_t texture_id() { return texture_id_; } + + private: + struct FrameSize { + size_t width; + size_t height; + }; + FrameSize last_frame_size_ = {0, 0}; + bool first_frame_rendered = false; + TextureRegistrar *registrar_ = nullptr; + std::unique_ptr> event_channel_; + std::unique_ptr> event_sink_; + int64_t texture_id_ = -1; + scoped_refptr track_ = nullptr; + scoped_refptr frame_; + std::unique_ptr texture_; + std::shared_ptr pixel_buffer_; + mutable std::shared_ptr rgb_buffer_; + mutable std::mutex mutex_; + RTCVideoFrame::VideoRotation rotation_ = RTCVideoFrame::kVideoRotation_0; +}; + +class FlutterVideoRendererManager { + public: + FlutterVideoRendererManager(FlutterWebRTCBase *base); + + void CreateVideoRendererTexture( + std::unique_ptr> result); + + void SetMediaStream(int64_t texture_id, const std::string &stream_id); + + void VideoRendererDispose( + int64_t texture_id, std::unique_ptr> result); + + private: + FlutterWebRTCBase *base_; + std::map> renderers_; +}; + +} // namespace flutter_webrtc_plugin + +#endif // !FLUTTER_WEBRTC_RTC_VIDEO_RENDERER_HXX \ No newline at end of file diff --git a/windows/include/flutter_webrtc.h b/windows/include/flutter_webrtc.h new file mode 100644 index 0000000000..ab0bc2f899 --- /dev/null +++ b/windows/include/flutter_webrtc.h @@ -0,0 +1,40 @@ +#ifndef PLUGINS_FLUTTER_WEBRTC_HXX +#define PLUGINS_FLUTTER_WEBRTC_HXX + +#include +#include +#include + +#include "flutter_data_channel.h" +#include "flutter_media_stream.h" +#include "flutter_peerconnection.h" +#include "flutter_video_renderer.h" +#include "libwebrtc.h" + +namespace flutter_webrtc_plugin { +using namespace libwebrtc; + +class FlutterWebRTCPlugin : public flutter::Plugin { + public: + virtual flutter::BinaryMessenger *messenger() = 0; + + virtual flutter::TextureRegistrar *textures() = 0; +}; + +class FlutterWebRTC : public FlutterWebRTCBase, + public FlutterVideoRendererManager, + public FlutterMediaStream, + public FlutterPeerConnection, + public FlutterDataChannel { + public: + FlutterWebRTC(FlutterWebRTCPlugin *plugin); + virtual ~FlutterWebRTC(); + + void HandleMethodCall( + const flutter::MethodCall &method_call, + std::unique_ptr> result); +}; + +} // namespace flutter_webrtc_plugin + +#endif // PLUGINS_FLUTTER_WEBRTC_HXX diff --git a/windows/include/flutter_webrtc/flutter_web_r_t_c_plugin.h b/windows/include/flutter_webrtc/flutter_web_r_t_c_plugin.h new file mode 100644 index 0000000000..5069b269fa --- /dev/null +++ b/windows/include/flutter_webrtc/flutter_web_r_t_c_plugin.h @@ -0,0 +1,23 @@ +#ifndef FLUTTER_PLUGIN_FLUTTER_WEBRTC_PLUGIN_H_ +#define FLUTTER_PLUGIN_FLUTTER_WEBRTC_PLUGIN_H_ + +#include + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +FLUTTER_PLUGIN_EXPORT void FlutterWebRTCPluginRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_PLUGIN_FLUTTER_WEBRTC_PLUGIN_H_ diff --git a/windows/include/flutter_webrtc/flutter_webrtc_plugin.h b/windows/include/flutter_webrtc/flutter_webrtc_plugin.h new file mode 100644 index 0000000000..b41f8b277a --- /dev/null +++ b/windows/include/flutter_webrtc/flutter_webrtc_plugin.h @@ -0,0 +1,31 @@ +#ifndef PLUGINS_FLUTTER_WEBRTC_PLUGIN_WINDOWS_H_ +#define PLUGINS_FLUTTER_WEBRTC_PLUGIN_WINDOWS_H_ + +#include + +#if defined(_WINDOWS) +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) +#endif +#else +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) +#else +#define FLUTTER_PLUGIN_EXPORT +#endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +FLUTTER_PLUGIN_EXPORT void FlutterWebRTCPluginRegisterWithRegistrar( + FlutterDesktopPluginRegistrarRef registrar); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // PLUGINS_FLUTTER_WEBRTC_PLUGIN_WINDOWS_H_ diff --git a/windows/include/flutter_webrtc_base.h b/windows/include/flutter_webrtc_base.h new file mode 100644 index 0000000000..a4e83514df --- /dev/null +++ b/windows/include/flutter_webrtc_base.h @@ -0,0 +1,155 @@ +#ifndef FLUTTER_WEBRTC_BASE_HXX +#define FLUTTER_WEBRTC_BASE_HXX + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "libwebrtc.h" +#include "rtc_audio_device.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" + +#ifdef WIN32 +#undef strncpy +#define strncpy strncpy_s +#endif + +namespace flutter_webrtc_plugin { + +using namespace libwebrtc; +using namespace flutter; + +class FlutterVideoRenderer; +class FlutterRTCDataChannelObserver; +class FlutterPeerConnectionObserver; + +// foo.StringValue() becomes std::get(foo) +// foo.IsString() becomes std::holds_alternative(foo) + +template +inline bool TypeIs(const EncodableValue val) { + return std::holds_alternative(val); +} + +template +inline const T GetValue(EncodableValue val) { + return std::get(val); +} + +inline EncodableValue findEncodableValue(const EncodableMap &map, + const std::string &key) { + auto it = map.find(EncodableValue(key)); + if (it != map.end()) return it->second; + return EncodableValue(); +} + +inline EncodableMap findMap(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 EncodableMap(); +} + +inline std::string findString(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::string(); +} + +inline int findInt(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 -1; +} + +inline int64_t findLongInt(const EncodableMap &map, const std::string &key) +{ + auto it = map.find(EncodableValue(key)); + if (it != map.end() && TypeIs(it->second) || + TypeIs(it->second)) + return GetValue(it->second); + return -1; +} + +class FlutterWebRTCBase { + public: + friend class FlutterMediaStream; + friend class FlutterPeerConnection; + friend class FlutterVideoRendererManager; + friend class FlutterDataChannel; + friend class FlutterPeerConnectionObserver; + enum ParseConstraintType { kMandatory, kOptional }; + + public: + FlutterWebRTCBase(BinaryMessenger *messenger, TextureRegistrar *textures); + ~FlutterWebRTCBase(); + + std::string GenerateUUID(); + + RTCPeerConnection *PeerConnectionForId(const std::string &id); + + void RemovePeerConnectionForId(const std::string &id); + + scoped_refptr MediaStreamForId(const std::string &id); + + void RemoveStreamForId(const std::string &id); + + bool ParseConstraints(const EncodableMap &constraints, + RTCConfiguration *configuration); + + scoped_refptr ParseMediaConstraints( + const EncodableMap &constraints); + + bool ParseRTCConfiguration(const EncodableMap &map, + RTCConfiguration &configuration); + + private: + void ParseConstraints(const EncodableMap &src, + scoped_refptr mediaConstraints, + ParseConstraintType type = kMandatory); + + bool CreateIceServers(const EncodableList &iceServersArray, + IceServer *ice_servers); + + protected: + scoped_refptr factory_; + scoped_refptr audio_device_; + scoped_refptr video_device_; + RTCConfiguration configuration_; + + std::map> peerconnections_; + std::map> local_streams_; + std::map> media_tracks_; + std::map> data_channels_; + std::map> renders_; + std::map> + data_channel_observers_; + std::map> + peerconnection_observers_; + + protected: + BinaryMessenger *messenger_; + TextureRegistrar *textures_; +}; + +} // namespace flutter_webrtc_plugin + +#endif // !FLUTTER_WEBRTC_BASE_HXX diff --git a/windows/src/flutter_data_channel.cc b/windows/src/flutter_data_channel.cc new file mode 100644 index 0000000000..3749d64445 --- /dev/null +++ b/windows/src/flutter_data_channel.cc @@ -0,0 +1,155 @@ +#include "flutter_data_channel.h" + +#include + +namespace flutter_webrtc_plugin { + +FlutterRTCDataChannelObserver::FlutterRTCDataChannelObserver( + scoped_refptr data_channel, BinaryMessenger *messenger, + const std::string &name) + : event_channel_(new EventChannel( + messenger, name, &StandardMethodCodec::GetInstance())), + data_channel_(data_channel) { + auto handler = std::make_unique>( + [&]( + const flutter::EncodableValue* arguments, + std::unique_ptr>&& events) + -> std::unique_ptr> { + event_sink_ = std::move(events); + return nullptr; + }, + [&](const flutter::EncodableValue* arguments) + -> std::unique_ptr> { + event_sink_ = nullptr; + return nullptr; + }); + + event_channel_->SetStreamHandler(std::move(handler)); + data_channel_->RegisterObserver(this); +} + +FlutterRTCDataChannelObserver::~FlutterRTCDataChannelObserver() {} + +void FlutterDataChannel::CreateDataChannel( + const std::string &label, const EncodableMap &dataChannelDict, + RTCPeerConnection *pc, + std::unique_ptr> result) { + + RTCDataChannelInit init; + init.id = GetValue(dataChannelDict.find(EncodableValue("id"))->second); + + init.ordered = + GetValue(dataChannelDict.find(EncodableValue("ordered"))->second); + + if (dataChannelDict.find(EncodableValue("maxRetransmits")) != dataChannelDict.end()) { + init.maxRetransmits = GetValue( + dataChannelDict.find(EncodableValue("maxRetransmits"))->second); + } + + std::string protocol = "sctp"; + + if (dataChannelDict.find(EncodableValue("protocol")) == + dataChannelDict.end()) { + protocol = GetValue( + dataChannelDict.find(EncodableValue("protocol"))->second); + } + + strncpy(init.protocol, protocol.c_str(), protocol.size()); + + init.negotiated = + GetValue(dataChannelDict.find(EncodableValue("negotiated"))->second); + + scoped_refptr data_channel = + pc->CreateDataChannel(label.c_str(), &init); + + std::string event_channel = + "FlutterWebRTC/dataChannelEvent" + std::to_string(data_channel->id()); + + std::unique_ptr observer( + new FlutterRTCDataChannelObserver(data_channel, base_->messenger_, + event_channel)); + + base_->data_channel_observers_[data_channel->id()] = std::move(observer); + + EncodableMap params; + params[EncodableValue("id")] = EncodableValue(data_channel->id()); + params[EncodableValue("label")] = EncodableValue(data_channel->label()); + result->Success(EncodableValue(params)); +} + +void FlutterDataChannel::DataChannelSend( + RTCDataChannel *data_channel, const std::string &type, + const EncodableValue &data, + std::unique_ptr> result) { + bool is_binary = type == "binary"; + if (is_binary && TypeIs>(data)) { + std::vector binary = GetValue>(data); + data_channel->Send((const char *)&binary[0], (int)binary.size(), true); + } else { + std::string str = GetValue(data); + data_channel->Send(str.data(), (int)str.size(), false); + } + result->Success(nullptr); +} + +void FlutterDataChannel::DataChannelClose( + RTCDataChannel *data_channel, + std::unique_ptr> result) { + int id = data_channel->id(); + data_channel->Close(); + auto it = base_->data_channel_observers_.find(id); + if (it != base_->data_channel_observers_.end()) + base_->data_channel_observers_.erase(it); + result->Success(nullptr); +} + +RTCDataChannel *FlutterDataChannel::DataChannelFormId(int id) { + auto it = base_->data_channel_observers_.find(id); + + if (it != base_->data_channel_observers_.end()) { + FlutterRTCDataChannelObserver *observer = it->second.get(); + scoped_refptr data_channel = observer->data_channel(); + return data_channel.get(); + } + return nullptr; +} + +static const char *DataStateString(RTCDataChannelState state) { + switch (state) { + case RTCDataChannelConnecting: + return "connecting"; + case RTCDataChannelOpen: + return "open"; + case RTCDataChannelClosing: + return "closing"; + case RTCDataChannelClosed: + return "closed"; + } + return ""; +} + +void FlutterRTCDataChannelObserver::OnStateChange(RTCDataChannelState state) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = EncodableValue("dataChannelStateChanged"); + params[EncodableValue("id")] = EncodableValue(data_channel_->id()); + params[EncodableValue("state")] = EncodableValue(DataStateString(state)); + event_sink_->Success(EncodableValue(params)); + } +} + +void FlutterRTCDataChannelObserver::OnMessage(const char *buffer, int length, + bool binary) { + + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = + EncodableValue ("dataChannelReceiveMessage"); + params[EncodableValue("id")] = EncodableValue(data_channel_->id()); + params[EncodableValue("type")] = EncodableValue(binary ? "binary" : "text"); + std::string str(buffer, length); + params[EncodableValue("data")] = binary ? EncodableValue(std::vector(str.begin(), str.end())) : EncodableValue(str); + event_sink_->Success(EncodableValue(params)); + } +} +} // namespace flutter_webrtc_plugin diff --git a/windows/src/flutter_media_stream.cc b/windows/src/flutter_media_stream.cc new file mode 100644 index 0000000000..c22a570ce3 --- /dev/null +++ b/windows/src/flutter_media_stream.cc @@ -0,0 +1,310 @@ +#include "flutter_media_stream.h" + +#define DEFAULT_WIDTH 1280 +#define DEFAULT_HEIGHT 720 +#define DEFAULT_FPS 30 + +namespace flutter_webrtc_plugin { + +void FlutterMediaStream::GetUserMedia( + const EncodableMap& constraints, + std::unique_ptr> result) { + std::string uuid = base_->GenerateUUID(); + scoped_refptr stream = + base_->factory_->CreateStream(uuid.c_str()); + + EncodableMap params; + params[EncodableValue("streamId")] = uuid; + + auto it = constraints.find(EncodableValue("audio")); + if (it != constraints.end()) { + EncodableValue audio = it->second; + if (TypeIs(audio)) { + if (true == GetValue(audio)) { + GetUserAudio(constraints, stream, params); + } + } else if (TypeIs(audio)) { + GetUserAudio(constraints, stream, params); + } + } else { + params[EncodableValue("audioTracks")] = EncodableValue(EncodableList()); + } + + it = constraints.find(EncodableValue("video")); + if (it != constraints.end()) { + EncodableValue video = it->second; + if (TypeIs(video)) { + if (true == GetValue(video)) { + GetUserVideo(constraints, stream, params); + } + } else if (TypeIs(video)) { + GetUserVideo(constraints, stream, params); + } + } else { + params[EncodableValue("videoTracks")] = EncodableValue(EncodableList()); + } + + base_->local_streams_[uuid] = stream; + result->Success(EncodableValue(params)); +} + +void addDefaultAudioConstraints( + scoped_refptr audioConstraints) { + audioConstraints->AddOptionalConstraint("googNoiseSuppression", "true"); + audioConstraints->AddOptionalConstraint("googEchoCancellation", "true"); + audioConstraints->AddOptionalConstraint("echoCancellation", "true"); + audioConstraints->AddOptionalConstraint("googEchoCancellation2", "true"); + audioConstraints->AddOptionalConstraint("googDAEchoCancellation", "true"); +} + +void FlutterMediaStream::GetUserAudio(const EncodableMap& constraints, + scoped_refptr stream, + EncodableMap& params) { + bool enable_audio = false; + scoped_refptr audioConstraints; + auto it = constraints.find(EncodableValue("audio")); + if (it != constraints.end()) { + EncodableValue audio = it->second; + if (TypeIs(audio)) { + audioConstraints = RTCMediaConstraints::Create(); + addDefaultAudioConstraints(audioConstraints); + enable_audio = GetValue(audio); + } + if (TypeIs(audio)) { + audioConstraints = + base_->ParseMediaConstraints(GetValue(audio)); + enable_audio = true; + } + } + + // TODO: Select audio device by sourceId, + + if (enable_audio) { + scoped_refptr source = + base_->factory_->CreateAudioSource("audio_input"); + std::string uuid = base_->GenerateUUID(); + scoped_refptr track = + base_->factory_->CreateAudioTrack(source, uuid.c_str()); + + std::string track_id = track->id(); + + EncodableMap track_info; + track_info[EncodableValue("id")] = track->id(); + track_info[EncodableValue("label")] = track->id(); + track_info[EncodableValue("kind")] = track->kind(); + track_info[EncodableValue("enabled")] = track->enabled(); + + EncodableList audioTracks; + audioTracks.push_back(EncodableValue(track_info)); + params[EncodableValue("audioTracks")] = EncodableValue(audioTracks); + stream->AddTrack(track); + } +} + +std::string getFacingMode(const EncodableMap& mediaConstraints) { + return mediaConstraints.find(EncodableValue("facingMode")) != + mediaConstraints.end() + ? GetValue(mediaConstraints.find(EncodableValue("facingMode")) + ->second) + : ""; +} + +std::string getSourceIdConstraint(const EncodableMap& mediaConstraints) { + auto it = mediaConstraints.find(EncodableValue("optional")); + if (it != mediaConstraints.end() && + TypeIs(it->second)) { + EncodableList optional = GetValue(it->second); + for (size_t i = 0, size = optional.size(); i < size; i++) { + if (TypeIs(optional[i])) { + EncodableMap option = GetValue(optional[i]); + auto it2 = option.find(EncodableValue("sourceId")); + if (it2 != option.end() && TypeIs(it2->second)) { + return GetValue(it2->second); + } + } + } + } + return ""; +} + +void FlutterMediaStream::GetUserVideo(const EncodableMap& constraints, + scoped_refptr stream, + EncodableMap& params) { + EncodableMap video_constraints; + EncodableMap video_mandatory; + auto it = constraints.find(EncodableValue("video")); + if (it != constraints.end() && TypeIs(it->second)) { + EncodableMap video_map = GetValue(it->second); + if (video_map.find(EncodableValue("mandatory")) != video_map.end()) { + video_mandatory = + GetValue(video_map.find(EncodableValue("mandatory"))->second); + } + } + + std::string facing_mode = getFacingMode(video_constraints); + //bool isFacing = facing_mode == "" || facing_mode != "environment"; + std::string sourceId = getSourceIdConstraint(video_constraints); + /* + int width = video_mandatory["minWidth"].isNumeric() + ? video_mandatory["minWidth"].asInt() + : DEFAULT_WIDTH; + int height = video_mandatory["minHeight"].isNumeric() + ? video_mandatory["minHeight"].asInt() + : DEFAULT_HEIGHT; + int fps = video_mandatory["minFrameRate"].isNumeric() + ? video_mandatory["minFrameRate"].asInt() + : DEFAULT_FPS; + */ + scoped_refptr video_capturer; + char strNameUTF8[256]; + char strGuidUTF8[256]; + int nb_video_devices = base_->video_device_->NumberOfDevices(); + + for (int i = 0; i < nb_video_devices; i++) { + base_->video_device_->GetDeviceName(i, strNameUTF8, 256, strGuidUTF8, 256); + if (sourceId != "" && sourceId == strGuidUTF8) { + video_capturer = base_->video_device_->Create(strNameUTF8, i); + break; + } + } + + if (nb_video_devices == 0) return; + + if (!video_capturer.get()) { + base_->video_device_->GetDeviceName(0, strNameUTF8, 128, strGuidUTF8, 128); + video_capturer = base_->video_device_->Create(strNameUTF8, 0); + } + const char* video_source_label = "video_input"; + scoped_refptr source = base_->factory_->CreateVideoSource( + video_capturer, video_source_label, + base_->ParseMediaConstraints(video_constraints)); + + std::string uuid = base_->GenerateUUID(); + scoped_refptr track = + base_->factory_->CreateVideoTrack(source, uuid.c_str()); + + EncodableList videoTracks; + EncodableMap info; + info[EncodableValue("id")] = track->id(); + info[EncodableValue("label")] = track->id(); + info[EncodableValue("kind")] = track->kind(); + info[EncodableValue("enabled")] = track->enabled(); + videoTracks.push_back(EncodableValue(info)); + params[EncodableValue("videoTracks")] = EncodableValue(videoTracks); + stream->AddTrack(track); +} + +void FlutterMediaStream::GetSources( + std::unique_ptr> result) { + EncodableList sources; + + int nb_audio_devices = base_->audio_device_->RecordingDevices(); + char strNameUTF8[128]; + char strGuidUTF8[128]; + + for (uint16_t i = 0; i < nb_audio_devices; i++) { + base_->audio_device_->RecordingDeviceName(i, strNameUTF8, strGuidUTF8); + EncodableMap audio; + audio[EncodableValue("label")] = std::string(strNameUTF8); + audio[EncodableValue("deviceId")] = std::string(strGuidUTF8); + audio[EncodableValue("facing")] = ""; + audio[EncodableValue("kind")] = "audioinput"; + sources.push_back(EncodableValue(audio)); + } + + nb_audio_devices = base_->audio_device_->PlayoutDevices(); + for (uint16_t i = 0; i < nb_audio_devices; i++) { + base_->audio_device_->PlayoutDeviceName(i, strNameUTF8, strGuidUTF8); + EncodableMap audio; + audio[EncodableValue("label")] = std::string(strGuidUTF8); + audio[EncodableValue("deviceId")] = std::string(strNameUTF8); + audio[EncodableValue("facing")] = ""; + audio[EncodableValue("kind")] = "audiooutput"; + sources.push_back(EncodableValue(audio)); + } + + int nb_video_devices = base_->video_device_->NumberOfDevices(); + for (int i = 0; i < nb_video_devices; i++) { + base_->video_device_->GetDeviceName(i, strNameUTF8, 128, strGuidUTF8, 128); + EncodableMap video; + video[EncodableValue("label")] = std::string(strGuidUTF8); + video[EncodableValue("deviceId")] = std::string(strNameUTF8); + video[EncodableValue("facing")] = i == 1 ? "front" : "back"; + video[EncodableValue("kind")] = "videoinput"; + sources.push_back(EncodableValue(video)); + } + EncodableMap params; + params[EncodableValue("sources")] = sources; + result->Success(EncodableValue(params)); +} + +void FlutterMediaStream::MediaStreamGetTracks( + const std::string& stream_id, + std::unique_ptr> result) { + scoped_refptr stream = base_->MediaStreamForId(stream_id); + + if (stream) { + EncodableMap params; + EncodableList audioTracks; + for (auto track : stream->GetAudioTracks()) { + EncodableMap info; + info[EncodableValue("id")] = track->id(); + info[EncodableValue("label")] = track->id(); + info[EncodableValue("kind")] = track->kind(); + info[EncodableValue("enabled")] = track->enabled(); + info[EncodableValue("remote")] = true; + info[EncodableValue("readyState")] = "live"; + audioTracks.push_back(EncodableValue(info)); + } + params[EncodableValue("audioTracks")] = audioTracks; + + EncodableList videoTracks; + for (auto track : stream->GetVideoTracks()) { + EncodableMap info; + info[EncodableValue("id")] = track->id(); + info[EncodableValue("label")] = track->id(); + info[EncodableValue("kind")] = track->kind(); + info[EncodableValue("enabled")] = track->enabled(); + info[EncodableValue("remote")] = true; + info[EncodableValue("readyState")] = "live"; + videoTracks.push_back(EncodableValue("info")); + } + params[EncodableValue("videoTracks")] = videoTracks; + + result->Success(EncodableValue("params")); + } else { + result->Error("MediaStreamGetTracksFailed", + "MediaStreamGetTracks() media stream is null !"); + } +} + +void FlutterMediaStream::MediaStreamDispose( + const std::string& stream_id, + std::unique_ptr> result) { + scoped_refptr stream = base_->MediaStreamForId(stream_id); + AudioTrackVector audio_tracks = stream->GetAudioTracks(); + size_t track_size = audio_tracks.size(); + for (size_t i = 0; i < track_size; i++) { + stream->RemoveTrack(audio_tracks.at(i)); + } + VideoTrackVector video_tracks = stream->GetVideoTracks(); + track_size = video_tracks.size(); + for (size_t i = 0; i < track_size; i++) { + stream->RemoveTrack(video_tracks.at(i)); + } + base_->RemoveStreamForId(stream_id); + result->Success(); +} + +void FlutterMediaStream::MediaStreamTrackSetEnable( + const std::string& track_id, + std::unique_ptr> result) {} + +void FlutterMediaStream::MediaStreamTrackSwitchCamera( + const std::string& track_id, + std::unique_ptr> result) {} + +void FlutterMediaStream::MediaStreamTrackDispose( + const std::string& track_id, + std::unique_ptr> result) {} +} // namespace flutter_webrtc_plugin diff --git a/windows/src/flutter_peerconnection.cc b/windows/src/flutter_peerconnection.cc new file mode 100644 index 0000000000..b0ed2f3f6c --- /dev/null +++ b/windows/src/flutter_peerconnection.cc @@ -0,0 +1,357 @@ +#include "flutter_peerconnection.h" + +#include "flutter_data_channel.h" + +namespace flutter_webrtc_plugin { + +void FlutterPeerConnection::CreateRTCPeerConnection( + const EncodableMap &configurationMap, const EncodableMap &constraintsMap, + std::unique_ptr> result) { + // std::cout << " configuration = " << configurationMap.StringValue() << + // std::endl; + base_->ParseRTCConfiguration(configurationMap, base_->configuration_); + // std::cout << " constraints = " << constraintsMap.StringValue() << + // std::endl; + scoped_refptr constraints = + base_->ParseMediaConstraints(constraintsMap); + + std::string uuid = base_->GenerateUUID(); + scoped_refptr pc = + base_->factory_->Create(base_->configuration_, constraints); + base_->peerconnections_[uuid] = pc; + + std::string event_channel = "FlutterWebRTC/peerConnectoinEvent" + uuid; + + std::unique_ptr observer( + new FlutterPeerConnectionObserver(base_, pc, base_->messenger_, + event_channel)); + + base_->peerconnection_observers_[uuid] = std::move(observer); + + EncodableMap params; + params[EncodableValue("peerConnectionId")] = uuid; + result->Success(EncodableValue(params)); +} + +void FlutterPeerConnection::RTCPeerConnectionClose( + RTCPeerConnection *pc, const std::string &uuid, + std::unique_ptr> result) { + pc->Close(); + auto it = base_->peerconnection_observers_.find(uuid); + if (it != base_->peerconnection_observers_.end()) + base_->peerconnection_observers_.erase(it); + + result->Success(nullptr); +} + +void FlutterPeerConnection::CreateOffer( + const EncodableMap &constraintsMap, RTCPeerConnection *pc, + std::unique_ptr> result) { + scoped_refptr constraints = + base_->ParseMediaConstraints(constraintsMap); + std::shared_ptr> result_ptr(result.release()); + pc->CreateOffer( + [result_ptr](const char *sdp, const char *type) { + EncodableMap params; + params[EncodableValue("sdp")] = sdp; + params[EncodableValue("type")] = type; + result_ptr->Success(EncodableValue(params)); + }, + [result_ptr](const char *error) { + result_ptr->Error("createOfferFailed", error); + }, + constraints); +} + +void FlutterPeerConnection::CreateAnswer( + const EncodableMap &constraintsMap, RTCPeerConnection *pc, + std::unique_ptr> result) { + scoped_refptr constraints = + base_->ParseMediaConstraints(constraintsMap); + std::shared_ptr> result_ptr(result.release()); + pc->CreateAnswer( + [result_ptr](const char *sdp, const char *type) { + EncodableMap params; + params[EncodableValue("sdp")] = sdp; + params[EncodableValue("type")] = type; + result_ptr->Success(EncodableValue(params)); + }, + [result_ptr](const std::string &error) { + result_ptr->Error("createAnswerFailed", error); + }, + constraints); +} + +void FlutterPeerConnection::SetLocalDescription( + RTCSessionDescription *sdp, RTCPeerConnection *pc, + std::unique_ptr> result) { + std::shared_ptr> result_ptr(result.release()); + pc->SetLocalDescription( + sdp->sdp(), sdp->type(), [result_ptr]() { result_ptr->Success(nullptr); }, + [result_ptr](const char *error) { + result_ptr->Error("setLocalDescriptionFailed", error); + }); +} + +void FlutterPeerConnection::SetRemoteDescription( + RTCSessionDescription *sdp, RTCPeerConnection *pc, + std::unique_ptr> result) { + std::shared_ptr> result_ptr(result.release()); + pc->SetRemoteDescription( + sdp->sdp(), sdp->type(), [result_ptr]() { result_ptr->Success(nullptr); }, + [result_ptr](const char *error) { + result_ptr->Error("setRemoteDescriptionFailed", error); + }); +} + +void FlutterPeerConnection::AddIceCandidate( + RTCIceCandidate *candidate, RTCPeerConnection *pc, + std::unique_ptr> result) { + pc->AddCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(), + candidate->candidate()); + result->Success(nullptr); +} + +void FlutterPeerConnection::GetStats( + const std::string &track_id, RTCPeerConnection *pc, + std::unique_ptr> result) {} + +FlutterPeerConnectionObserver::FlutterPeerConnectionObserver( + FlutterWebRTCBase *base, scoped_refptr peerconnection, + BinaryMessenger *messenger, const std::string &channel_name) + : event_channel_(new EventChannel( + messenger, channel_name, &StandardMethodCodec::GetInstance())), + peerconnection_(peerconnection), + base_(base) { + auto handler = std::make_unique>( + [&]( + const flutter::EncodableValue* arguments, + std::unique_ptr>&& events) + -> std::unique_ptr> { + event_sink_ = std::move(events); + return nullptr; + }, + [&](const flutter::EncodableValue* arguments) + -> std::unique_ptr> { + event_sink_ = nullptr; + return nullptr; + }); + + event_channel_->SetStreamHandler(std::move(handler)); + peerconnection->RegisterRTCPeerConnectionObserver(this); +} + +static const char *iceConnectionStateString(RTCIceConnectionState state) { + switch (state) { + case RTCIceConnectionStateNew: + return "new"; + case RTCIceConnectionStateChecking: + return "checking"; + case RTCIceConnectionStateConnected: + return "connected"; + case RTCIceConnectionStateCompleted: + return "completed"; + case RTCIceConnectionStateFailed: + return "failed"; + case RTCIceConnectionStateDisconnected: + return "disconnected"; + case RTCIceConnectionStateClosed: + return "closed"; + } + return ""; +} + +static const char *signalingStateString(RTCSignalingState state) { + switch (state) { + case RTCSignalingStateStable: + return "stable"; + case RTCSignalingStateHaveLocalOffer: + return "have-local-offer"; + case RTCSignalingStateHaveLocalPrAnswer: + return "have-local-pranswer"; + case RTCSignalingStateHaveRemoteOffer: + return "have-remote-offer"; + case RTCSignalingStateHaveRemotePrAnswer: + return "have-remote-pranswer"; + case RTCSignalingStateClosed: + return "closed"; + } + return ""; +} +void FlutterPeerConnectionObserver::OnSignalingState(RTCSignalingState state) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "iceConnectionState"; + params[EncodableValue("state")] = signalingStateString(state); + event_sink_->Success(EncodableValue(params)); + } +} + +static const char *iceGatheringStateString(RTCIceGatheringState state) { + switch (state) { + case RTCIceGatheringStateNew: + return "new"; + case RTCIceGatheringStateGathering: + return "gathering"; + case RTCIceGatheringStateComplete: + return "complete"; + } + return ""; +} + +void FlutterPeerConnectionObserver::OnIceGatheringState( + RTCIceGatheringState state) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "iceGatheringState"; + params[EncodableValue("state")] = iceGatheringStateString(state); + event_sink_->Success(EncodableValue(params)); + } +} + +void FlutterPeerConnectionObserver::OnIceConnectionState( + RTCIceConnectionState state) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "signalingState"; + params[EncodableValue("state")] = iceConnectionStateString(state); + event_sink_->Success(EncodableValue(params)); + } +} + +void FlutterPeerConnectionObserver::OnIceCandidate( + scoped_refptr candidate) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "onCandidate"; + EncodableMap cand; + cand[EncodableValue("candidate")] = candidate->candidate(); + cand[EncodableValue("sdpMLineIndex")] = candidate->sdp_mline_index(); + cand[EncodableValue("sdpMid")] = candidate->sdp_mid(); + params[EncodableValue("candidate")] = cand; + event_sink_->Success(EncodableValue(params)); + } +} + +void FlutterPeerConnectionObserver::OnAddStream( + scoped_refptr stream) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "onAddStream"; + params[EncodableValue("streamId")] = stream->label(); + EncodableList audioTracks; + for (auto track : stream->GetAudioTracks()) { + EncodableMap audioTrack; + audioTrack[EncodableValue("id")] = track->id(); + audioTrack[EncodableValue("label")] = track->id(); + audioTrack[EncodableValue("kind")] = track->kind(); + audioTrack[EncodableValue("enabled")] = track->enabled(); + audioTrack[EncodableValue("remote")] = true; + audioTrack[EncodableValue("readyState")] = "live"; + + audioTracks.push_back(EncodableValue(audioTrack)); + } + params[EncodableValue("audioTracks")] = audioTracks; + + EncodableList videoTracks; + for (auto track : stream->GetVideoTracks()) { + EncodableMap videoTrack; + + videoTrack[EncodableValue("id")] = track->id(); + videoTrack[EncodableValue("label")] = track->id(); + videoTrack[EncodableValue("kind")] = track->kind(); + videoTrack[EncodableValue("enabled")] = track->enabled(); + videoTrack[EncodableValue("remote")] = true; + videoTrack[EncodableValue("readyState")] = "live"; + + videoTracks.push_back(EncodableValue(videoTrack)); + } + + remote_streams_[stream->label()] = + scoped_refptr(stream); + params[EncodableValue("videoTracks")] = videoTracks; + event_sink_->Success(EncodableValue(params)); + } +} + +void FlutterPeerConnectionObserver::OnRemoveStream( + scoped_refptr stream) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "onRemoveStream"; + params[EncodableValue("streamId")] = stream->label(); + event_sink_->Success(EncodableValue(params)); + } + RemoveStreamForId(stream->label()); +} + +void FlutterPeerConnectionObserver::OnAddTrack( + scoped_refptr stream, scoped_refptr track) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "onAddTrack"; + params[EncodableValue("streamId")] = stream->label(); + params[EncodableValue("trackId")] = track->id(); + + EncodableMap audioTrack; + audioTrack[EncodableValue("id")] = track->id(); + audioTrack[EncodableValue("label")] = track->id(); + audioTrack[EncodableValue("kind")] = track->kind(); + audioTrack[EncodableValue("enabled")] = track->enabled(); + audioTrack[EncodableValue("remote")] = true; + audioTrack[EncodableValue("readyState")] = "live"; + params[EncodableValue("track")] = audioTrack; + + event_sink_->Success(EncodableValue(params)); + } +} + +void FlutterPeerConnectionObserver::OnRemoveTrack( + scoped_refptr stream, scoped_refptr track) { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "onRemoveTrack"; + params[EncodableValue("streamId")] = stream->label(); + params[EncodableValue("trackId")] = track->id(); + + EncodableMap videoTrack; + videoTrack[EncodableValue("id")] = track->id(); + videoTrack[EncodableValue("label")] = track->id(); + videoTrack[EncodableValue("kind")] = track->kind(); + videoTrack[EncodableValue("enabled")] = track->enabled(); + videoTrack[EncodableValue("remote")] = true; + videoTrack[EncodableValue("readyState")] = "live"; + params[EncodableValue("track")] = videoTrack; + + event_sink_->Success(EncodableValue(params)); + } +} + +void FlutterPeerConnectionObserver::OnDataChannel( + scoped_refptr data_channel) { + std::string event_channel = + "FlutterWebRTC/dataChannelEvent" + std::to_string(data_channel->id()); + + std::unique_ptr observer( + new FlutterRTCDataChannelObserver(data_channel, base_->messenger_, + event_channel)); + + base_->data_channel_observers_[data_channel->id()] = std::move(observer); + if (event_sink_) { + EncodableMap params; + params[EncodableValue("event")] = "didOpenDataChannel"; + params[EncodableValue("id")] = data_channel->id(); + params[EncodableValue("label")] = data_channel->label(); + event_sink_->Success(EncodableValue(params)); + } +} + +void FlutterPeerConnectionObserver::OnRenegotiationNeeded() { + if (event_sink_ != nullptr) { + EncodableMap params; + params[EncodableValue("event")] = "onRenegotiationNeeded"; + event_sink_->Success(EncodableValue(params)); + } +} + +} // namespace flutter_webrtc_plugin diff --git a/windows/src/flutter_video_renderer.cc b/windows/src/flutter_video_renderer.cc new file mode 100644 index 0000000000..c5538e6866 --- /dev/null +++ b/windows/src/flutter_video_renderer.cc @@ -0,0 +1,162 @@ +#include "flutter_video_renderer.h" + +namespace flutter_webrtc_plugin { + +FlutterVideoRenderer::FlutterVideoRenderer(TextureRegistrar *registrar, + BinaryMessenger *messenger) + : registrar_(registrar) { + + texture_ = + std::make_unique(flutter::PixelBufferTexture( + [this](size_t width, + size_t height) -> const FlutterDesktopPixelBuffer* { + return this->CopyPixelBuffer(width, height); + })); + + texture_id_ = registrar_->RegisterTexture(texture_.get()); + + std::string event_channel = + "FlutterWebRTC/Texture" + std::to_string(texture_id_); + event_channel_.reset(new EventChannel( + messenger, event_channel, &StandardMethodCodec::GetInstance())); + + auto handler = std::make_unique>( + [&]( + const flutter::EncodableValue* arguments, + std::unique_ptr>&& events) + -> std::unique_ptr> { + event_sink_ = std::move(events); + return nullptr; + }, + [&](const flutter::EncodableValue* arguments) + -> std::unique_ptr> { + event_sink_ = nullptr; + return nullptr; + }); + + event_channel_->SetStreamHandler(std::move(handler)); +} + +const FlutterDesktopPixelBuffer* FlutterVideoRenderer::CopyPixelBuffer( + size_t width, + size_t height) const { + mutex_.lock(); + if (pixel_buffer_.get() && frame_.get()) { + if (pixel_buffer_->width != frame_->width() || + pixel_buffer_->height != frame_->height()) { + size_t buffer_size = (frame_->width() * frame_->height()) * (32 >> 3); + rgb_buffer_.reset(new uint8_t[buffer_size]); + pixel_buffer_->width = frame_->width(); + pixel_buffer_->height = frame_->height(); + } + + frame_->ConvertToARGB(RTCVideoFrame::Type::kABGR, rgb_buffer_.get(), 0, + (int)pixel_buffer_->width, + (int)pixel_buffer_->height); + + pixel_buffer_->buffer = rgb_buffer_.get(); + mutex_.unlock(); + return pixel_buffer_.get(); + } + mutex_.unlock(); + return nullptr; +} + +void FlutterVideoRenderer::OnFrame(scoped_refptr frame) { + if (!first_frame_rendered) { + if (event_sink_) { + EncodableMap params; + params[EncodableValue("event")] = "didFirstFrameRendered"; + params[EncodableValue("id")] = texture_id_; + event_sink_->Success(EncodableValue(params)); + } + pixel_buffer_.reset(new FlutterDesktopPixelBuffer()); + pixel_buffer_->width = 0; + pixel_buffer_->height = 0; + first_frame_rendered = true; + } + if (rotation_ != frame->rotation()) { + if (event_sink_) { + EncodableMap params; + params[EncodableValue("event")] = "didTextureChangeRotation"; + params[EncodableValue("id")] = texture_id_; + params[EncodableValue("rotation")] = (int32_t)frame->rotation(); + event_sink_->Success(EncodableValue(params)); + } + rotation_ = frame->rotation(); + } + if (last_frame_size_.width != frame->width() || + last_frame_size_.height != frame->height()) { + if (event_sink_) { + EncodableMap params; + params[EncodableValue("event")] = "didTextureChangeVideoSize"; + params[EncodableValue("id")] = texture_id_; + params[EncodableValue("width")] = (int32_t)frame->width(); + params[EncodableValue("height")] = (int32_t)frame->height(); + event_sink_->Success(EncodableValue(params)); + } + last_frame_size_ = {(size_t)frame->width(), (size_t)frame->height()}; + } + mutex_.lock(); + frame_ = frame; + mutex_.unlock(); + registrar_->MarkTextureFrameAvailable(texture_id_); +} + +void FlutterVideoRenderer::SetVideoTrack(scoped_refptr track) { + if (track_ != track) { + if (track_) track_->RemoveRenderer(this); + track_ = track; + last_frame_size_ = {0, 0}; + first_frame_rendered = false; + if (track_) track_->AddRenderer(this); + } +} + +FlutterVideoRendererManager::FlutterVideoRendererManager( + FlutterWebRTCBase *base) + : base_(base) {} + +void FlutterVideoRendererManager::CreateVideoRendererTexture( + std::unique_ptr> result) { + std::unique_ptr texture( + new FlutterVideoRenderer(base_->textures_, base_->messenger_)); + int64_t texture_id = texture->texture_id(); + renderers_[texture_id] = std::move(texture); + EncodableMap params; + params[EncodableValue("textureId")] = texture_id; + result->Success(EncodableValue(params)); +} + +void FlutterVideoRendererManager::SetMediaStream(int64_t texture_id, + const std::string &stream_id) { + scoped_refptr stream = base_->MediaStreamForId(stream_id); + + auto it = renderers_.find(texture_id); + if (it != renderers_.end()) { + FlutterVideoRenderer *renderer = it->second.get(); + if (stream.get()) { + VideoTrackVector tracks = stream->GetVideoTracks(); + if (tracks.size() > 0) { + renderer->SetVideoTrack(tracks.at(0)); + } + } else { + renderer->SetVideoTrack(nullptr); + } + } +} + +void FlutterVideoRendererManager::VideoRendererDispose( + int64_t texture_id, std::unique_ptr> result) { + auto it = renderers_.find(texture_id); + if (it != renderers_.end()) { + base_->textures_->UnregisterTexture(texture_id); + renderers_.erase(it); + result->Success(); + return; + } + result->Error("VideoRendererDisposeFailed", + "VideoRendererDispose() texture not found!"); +} + +} // namespace flutter_webrtc_plugin \ No newline at end of file diff --git a/windows/src/flutter_webrtc.cc b/windows/src/flutter_webrtc.cc new file mode 100644 index 0000000000..7d8122f9ca --- /dev/null +++ b/windows/src/flutter_webrtc.cc @@ -0,0 +1,335 @@ +#include "flutter_webrtc.h" + +#include "flutter_webrtc/flutter_web_r_t_c_plugin.h" + +namespace flutter_webrtc_plugin { + +FlutterWebRTC::FlutterWebRTC(FlutterWebRTCPlugin *plugin) + : FlutterWebRTCBase::FlutterWebRTCBase(plugin->messenger(), + plugin->textures()), + FlutterVideoRendererManager::FlutterVideoRendererManager(this), + FlutterMediaStream::FlutterMediaStream(this), + FlutterPeerConnection::FlutterPeerConnection(this), + FlutterDataChannel::FlutterDataChannel(this){} + +FlutterWebRTC::~FlutterWebRTC() {} + +void FlutterWebRTC::HandleMethodCall( + const flutter::MethodCall &method_call, + std::unique_ptr> result) { + if (method_call.method_name().compare("createPeerConnection") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const EncodableMap configuration = findMap(params, "configuration"); + const EncodableMap constraints = findMap(params, "constraints"); + CreateRTCPeerConnection(configuration, constraints, std::move(result)); + } else if (method_call.method_name().compare("getUserMedia") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const EncodableMap constraints = findMap(params, "constraints"); + GetUserMedia(constraints, std::move(result)); + } else if (method_call.method_name().compare("getDisplayMedia") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const EncodableMap constraints = findMap(params, "constraints"); + result->NotImplemented(); + } else if (method_call.method_name().compare("getSources") == 0) { + GetSources(std::move(result)); + } else if (method_call.method_name().compare("mediaStreamGetTracks") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const std::string streamId = findString(params, "streamId"); + MediaStreamGetTracks(streamId, std::move(result)); + } else if (method_call.method_name().compare("createOffer") == 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"); + const EncodableMap constraints = findMap(params, "constraints"); + RTCPeerConnection *pc = PeerConnectionForId(peerConnectionId); + if (pc == nullptr) { + result->Error("createOfferFailed", + "createOffer() peerConnection is null"); + return; + } + CreateOffer(constraints, pc, std::move(result)); + } else if (method_call.method_name().compare("createAnswer") == 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"); + const EncodableMap constraints = findMap(params, "constraints"); + RTCPeerConnection *pc = PeerConnectionForId(peerConnectionId); + if (pc == nullptr) { + result->Error("createAnswerFailed", + "createAnswer() peerConnection is null"); + return; + } + CreateAnswer(constraints, pc, std::move(result)); + } else if (method_call.method_name().compare("addStream") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const std::string streamId = findString(params, "streamId"); + const std::string peerConnectionId = findString(params, "peerConnectionId"); + + scoped_refptr stream = MediaStreamForId(streamId); + if (!stream) { + result->Error("addStreamFailed", "addStream() stream not found!"); + return; + } + RTCPeerConnection *pc = PeerConnectionForId(peerConnectionId); + if (pc == nullptr) { + result->Error("addStreamFailed", "addStream() peerConnection is null"); + return; + } + pc->AddStream(stream); + result->Success(nullptr); + } else if (method_call.method_name().compare("removeStream") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const std::string streamId = findString(params, "streamId"); + const std::string peerConnectionId = findString(params, "peerConnectionId"); + + scoped_refptr stream = MediaStreamForId(streamId); + if (!stream) { + result->Error("removeStreamFailed", "removeStream() stream not found!"); + return; + } + RTCPeerConnection *pc = PeerConnectionForId(peerConnectionId); + if (pc == nullptr) { + result->Error("removeStreamFailed", + "removeStream() peerConnection is null"); + return; + } + pc->RemoveStream(stream); + result->Success(nullptr); + } else if (method_call.method_name().compare("setLocalDescription") == 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"); + const EncodableMap constraints = findMap(params, "description"); + RTCPeerConnection *pc = PeerConnectionForId(peerConnectionId); + if (pc == nullptr) { + result->Error("setLocalDescriptionFailed", + "setLocalDescription() peerConnection is null"); + return; + } + + SdpParseError error; + scoped_refptr description = + CreateRTCSessionDescription(findString(constraints, "type").c_str(), + findString(constraints, "sdp").c_str(), + &error); + + SetLocalDescription(description.get(), pc, std::move(result)); + } else if (method_call.method_name().compare("setRemoteDescription") == 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"); + const EncodableMap constraints = findMap(params, "description"); + RTCPeerConnection *pc = PeerConnectionForId(peerConnectionId); + if (pc == nullptr) { + result->Error("setRemoteDescriptionFailed", + "setRemoteDescription() peerConnection is null"); + return; + } + + SdpParseError error; + scoped_refptr description = + CreateRTCSessionDescription(findString(constraints, "type").c_str(), + findString(constraints, "sdp").c_str(), + &error); + + SetRemoteDescription(description.get(), pc, std::move(result)); + } else if (method_call.method_name().compare("addCandidate") == 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"); + const EncodableMap constraints = findMap(params, "candidate"); + RTCPeerConnection *pc = PeerConnectionForId(peerConnectionId); + if (pc == nullptr) { + result->Error("addCandidateFailed", + "addCandidate() peerConnection is null"); + return; + } + + SdpParseError error; + scoped_refptr rtc_candidate = + CreateRTCIceCandidate(findString(constraints, "candidate").c_str(), + findString(constraints, "sdpMid").c_str(), + findInt(constraints, "sdpMLineIndex"), &error); + + AddIceCandidate(rtc_candidate.get(), pc, std::move(result)); + } else if (method_call.method_name().compare("getStats") == 0) { + } else if (method_call.method_name().compare("createDataChannel") == 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("createDataChannelFailed", + "createDataChannel() peerConnection is null"); + return; + } + + const std::string label = findString(params, "label"); + const EncodableMap dataChannelDict = findMap(params, "dataChannelDict"); + + CreateDataChannel(label, dataChannelDict, pc, std::move(result)); + } else if (method_call.method_name().compare("dataChannelSend") == 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("dataChannelSendFailed", + "dataChannelSend() peerConnection is null"); + return; + } + + int dataChannelId = findInt(params, "dataChannelId"); + const std::string type = findString(params, "type"); + const EncodableValue data = findEncodableValue(params, "data"); + RTCDataChannel *data_channel = DataChannelFormId(dataChannelId); + if (data_channel == nullptr) { + result->Error("dataChannelSendFailed", + "dataChannelSend() data_channel is null"); + return; + } + DataChannelSend(data_channel, type, data, std::move(result)); + } else if (method_call.method_name().compare("dataChannelClose") == 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("dataChannelCloseFailed", + "dataChannelClose() peerConnection is null"); + return; + } + + int dataChannelId = findInt(params, "dataChannelId"); + RTCDataChannel *data_channel = DataChannelFormId(dataChannelId); + if (data_channel == nullptr) { + result->Error("dataChannelCloseFailed", + "dataChannelClose() data_channel is null"); + return; + } + DataChannelClose(data_channel, std::move(result)); + } else if (method_call.method_name().compare("streamDispose") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const std::string stream_id = findString(params, "streamId"); + MediaStreamDispose(stream_id, std::move(result)); + } else if (method_call.method_name().compare("mediaStreamTrackSetEnable") == + 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const std::string track_id = findString(params, "trackId"); + MediaStreamTrackSetEnable(track_id, std::move(result)); + } else if (method_call.method_name().compare("trackDispose") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const std::string track_id = findString(params, "trackId"); + MediaStreamTrackDispose(track_id, std::move(result)); + } else if (method_call.method_name().compare("peerConnectionClose") == 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("peerConnectionCloseFailed", + "peerConnectionClose() peerConnection is null"); + return; + } + RTCPeerConnectionClose(pc, peerConnectionId, std::move(result)); + } else if (method_call.method_name().compare("createVideoRenderer") == 0) { + CreateVideoRendererTexture(std::move(result)); + } else if (method_call.method_name().compare("videoRendererDispose") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + int64_t texture_id = findLongInt(params, "textureId"); + VideoRendererDispose(texture_id, std::move(result)); + } else if (method_call.method_name().compare("videoRendererSetSrcObject") == + 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const std::string stream_id = findString(params, "streamId"); + int64_t texture_id = findLongInt(params, "textureId"); + SetMediaStream(texture_id, stream_id); + result->Success(nullptr); + } else if (method_call.method_name().compare( + "mediaStreamTrackSwitchCamera") == 0) { + if (!method_call.arguments()) { + result->Error("Bad Arguments", "Null constraints arguments received"); + return; + } + const EncodableMap params = GetValue(*method_call.arguments()); + const std::string track_id = findString(params, "trackId"); + MediaStreamTrackSwitchCamera(track_id, std::move(result)); + } else if (method_call.method_name().compare("setVolume") == 0) { + } else { + result->NotImplemented(); + } +} + +} // namespace flutter_webrtc_plugin diff --git a/windows/src/flutter_webrtc_base.cc b/windows/src/flutter_webrtc_base.cc new file mode 100644 index 0000000000..cdc46324b7 --- /dev/null +++ b/windows/src/flutter_webrtc_base.cc @@ -0,0 +1,255 @@ +#include "flutter_webrtc_base.h" + +#include "flutter_data_channel.h" +#include "flutter_peerconnection.h" + +namespace flutter_webrtc_plugin { + +FlutterWebRTCBase::FlutterWebRTCBase(BinaryMessenger *messenger, + TextureRegistrar *textures) + : messenger_(messenger), textures_(textures) { + LibWebRTC::Initialize(); + factory_ = LibWebRTC::CreateRTCPeerConnectionFactory(); + audio_device_ = factory_->GetAudioDevice(); + video_device_ = factory_->GetVideoDevice(); + memset(&configuration_.ice_servers, 0, sizeof(configuration_.ice_servers)); +} + +FlutterWebRTCBase::~FlutterWebRTCBase() { LibWebRTC::Terminate(); } + +std::string FlutterWebRTCBase::GenerateUUID() { + return uuidxx::uuid::Generate().ToString(false); +} + +RTCPeerConnection *FlutterWebRTCBase::PeerConnectionForId( + const std::string &id) { + auto it = peerconnections_.find(id); + + if (it != peerconnections_.end()) return (*it).second.get(); + + return nullptr; +} + +void FlutterWebRTCBase::RemovePeerConnectionForId(const std::string &id) { + auto it = peerconnections_.find(id); + if (it != peerconnections_.end()) peerconnections_.erase(it); +} + +scoped_refptr FlutterWebRTCBase::MediaStreamForId( + const std::string &id) { + + auto it = local_streams_.find(id); + if (it != local_streams_.end()) { + return (*it).second; + } + + for (auto kv : peerconnection_observers_) { + auto pco = kv.second.get(); + auto stream = pco->MediaStreamForId(id); + if (stream != nullptr) return stream; + } + + return nullptr; +} + +void FlutterWebRTCBase::RemoveStreamForId(const std::string &id) { + auto it = local_streams_.find(id); + if (it != local_streams_.end()) local_streams_.erase(it); +} + +bool FlutterWebRTCBase::ParseConstraints(const EncodableMap &constraints, + RTCConfiguration *configuration) { + memset(&configuration->ice_servers, 0, sizeof(configuration->ice_servers)); + return false; +} + +void FlutterWebRTCBase::ParseConstraints( + const EncodableMap &src, + scoped_refptr mediaConstraints, + ParseConstraintType type /*= kMandatory*/) { + for (auto kv : src) { + EncodableValue k = kv.first; + EncodableValue v = kv.second; + std::string key = GetValue(k); + std::string value; + if (TypeIs(v) || TypeIs(v)) { + } else if (TypeIs(v)) { + value = GetValue(v); + } else if (TypeIs(v)) { + value = std::to_string(GetValue(v)); + } else if (TypeIs(v)) { + value = std::to_string(GetValue(v)); + } else if (TypeIs(v)) { + value = GetValue(v) ? RTCMediaConstraints::kValueTrue + : RTCMediaConstraints::kValueFalse; + } else { + value = std::to_string(GetValue(v)); + } + if (type == kMandatory) + mediaConstraints->AddMandatoryConstraint(key.c_str(), value.c_str()); + else + mediaConstraints->AddOptionalConstraint(key.c_str(), value.c_str()); + } +} + +scoped_refptr FlutterWebRTCBase::ParseMediaConstraints( + const EncodableMap &constraints) { + scoped_refptr media_constraints = + RTCMediaConstraints::Create(); + + if (constraints.find(EncodableValue("mandatory")) != constraints.end()) { + auto it = constraints.find(EncodableValue("mandatory")); + const EncodableMap mandatory = GetValue(it->second); + ParseConstraints(mandatory, media_constraints, kMandatory); + } else { + // Log.d(TAG, "mandatory constraints are not a map"); + } + + auto it = constraints.find(EncodableValue("optional")); + if (it != constraints.end()) { + const EncodableValue optional = it->second; + if (TypeIs(optional)) { + ParseConstraints(GetValue(optional), media_constraints, + kOptional); + } else if (TypeIs(optional)) { + const EncodableList list = GetValue(optional); + for (size_t i = 0; i < list.size(); i++) { + ParseConstraints(GetValue(list[i]), media_constraints, kOptional); + } + } + } else { + // Log.d(TAG, "optional constraints are not an array"); + } + + return media_constraints; +} + +bool FlutterWebRTCBase::CreateIceServers(const EncodableList &iceServersArray, + IceServer *ice_servers) { + size_t size = iceServersArray.size(); + for (size_t i = 0; i < size; i++) { + IceServer &ice_server = ice_servers[i]; + EncodableMap iceServerMap = GetValue(iceServersArray[i]); + bool hasUsernameAndCredential = + iceServerMap.find(EncodableValue("username")) != iceServerMap.end() && + iceServerMap.find(EncodableValue("credential")) != iceServerMap.end(); + auto it = iceServerMap.find(EncodableValue("url")); + if (it != iceServerMap.end() && TypeIs(it->second)) { + if (hasUsernameAndCredential) { + std::string username = + GetValue(iceServerMap.find(EncodableValue("username"))->second); + std::string credential = + GetValue(iceServerMap.find(EncodableValue("credential")) + ->second); + std::string uri = GetValue(it->second); + strncpy(ice_server.username, username.c_str(), username.size()); + strncpy(ice_server.password, credential.c_str(), credential.size()); + strncpy(ice_server.uri, uri.c_str(), uri.size()); + } else { + std::string uri = GetValue(it->second); + strncpy(ice_server.uri, uri.c_str(), uri.size()); + } + } + it = iceServerMap.find(EncodableValue("urls")); + if (it != iceServerMap.end()) { + if (TypeIs(it->second)) { + if (hasUsernameAndCredential) { + std::string username = GetValue(iceServerMap.find(EncodableValue("username")) + ->second); + std::string credential = + GetValue(iceServerMap.find(EncodableValue("credential")) + ->second); + std::string uri = GetValue(it->second); + strncpy(ice_server.username, username.c_str(), username.size()); + strncpy(ice_server.password, credential.c_str(), credential.size()); + strncpy(ice_server.uri, uri.c_str(), uri.size()); + } else { + std::string uri = GetValue(it->second); + strncpy(ice_server.uri, uri.c_str(), uri.size()); + } + } + if (TypeIs(it->second)) { + const EncodableList urls = GetValue(it->second); + for (auto url : urls) { + const EncodableMap map = GetValue(url); + std::string value; + auto it2 = map.find(EncodableValue("url")); + if (it2 != map.end()) { + value = GetValue(it2->second); + if (hasUsernameAndCredential) { + std::string username = + GetValue(iceServerMap.find(EncodableValue("username")) + ->second); + std::string credential = + GetValue(iceServerMap.find(EncodableValue("credential")) + ->second); + strncpy(ice_server.username, username.c_str(), username.size()); + strncpy(ice_server.password, credential.c_str(), + credential.size()); + strncpy(ice_server.uri, value.c_str(), value.size()); + } else { + strncpy(ice_server.uri, value.c_str(), value.size()); + } + } + } + } + } + } + return size > 0; +} + +bool FlutterWebRTCBase::ParseRTCConfiguration(const EncodableMap &map, + RTCConfiguration &conf) { + auto it = map.find(EncodableValue("iceServers")); + if (it != map.end()) { + const EncodableList iceServersArray = GetValue(it->second); + CreateIceServers(iceServersArray, conf.ice_servers); + } + // iceTransportPolicy (public API) + it = map.find(EncodableValue("iceTransportPolicy")); + if (it != map.end() && TypeIs(it->second)) { + std::string v = GetValue(it->second); + if (v == "all") // public + conf.type = kAll; + else if (v == "relay") + conf.type = kRelay; + else if (v == "nohost") + conf.type = kNoHost; + else if (v == "none") + conf.type = kNone; + } + + // bundlePolicy (public api) + it = map.find(EncodableValue("bundlePolicy")); + if (it != map.end() && TypeIs(it->second)) { + std::string v = GetValue(it->second); + if (v == "balanced") // public + conf.bundle_policy = kBundlePolicyBalanced; + else if (v == "max-compat") // public + conf.bundle_policy = kBundlePolicyMaxCompat; + else if (v == "max-bundle") // public + conf.bundle_policy = kBundlePolicyMaxBundle; + } + + // rtcpMuxPolicy (public api) + it = map.find(EncodableValue("rtcpMuxPolicy")); + if (it != map.end() && TypeIs(it->second)) { + std::string v = GetValue(it->second); + if (v == "negotiate") // public + conf.rtcp_mux_policy = kRtcpMuxPolicyNegotiate; + else if (v == "require") // public + conf.rtcp_mux_policy = kRtcpMuxPolicyRequire; + } + + // FIXME: peerIdentity of type DOMString (public API) + // FIXME: certificates of type sequence (public API) + // iceCandidatePoolSize of type unsigned short, defaulting to 0 + it = map.find(EncodableValue("iceCandidatePoolSize")); + if (it != map.end()) { + conf.ice_candidate_pool_size = GetValue(it->second); + } + + return true; +} + +} // namespace flutter_webrtc_plugin diff --git a/windows/third_party/libwebrtc/include/base/atomicops.h b/windows/third_party/libwebrtc/include/base/atomicops.h new file mode 100644 index 0000000000..b68a2ae13c --- /dev/null +++ b/windows/third_party/libwebrtc/include/base/atomicops.h @@ -0,0 +1,75 @@ +/* + * Copyright 2011 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef LIB_WEBRTC_ATOMICOPS_H_ +#define LIB_WEBRTC_ATOMICOPS_H_ + +#if defined(WIN32) || defined(_WINDOWS) +// Include winsock2.h before including to maintain consistency with +// win32.h. We can't include win32.h directly here since it pulls in +// headers such as basictypes.h which causes problems in Chromium where webrtc +// exists as two separate projects, webrtc and libjingle. +#include +#endif // defined(WIN32) + +namespace libwebrtc { +class AtomicOps { + public: +#if defined(WIN32) || defined(_WINDOWS) + // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64. + static int Increment(volatile int* i) { + return ::InterlockedIncrement(reinterpret_cast(i)); + } + static int Decrement(volatile int* i) { + return ::InterlockedDecrement(reinterpret_cast(i)); + } + static int AcquireLoad(volatile const int* i) { return *i; } + static void ReleaseStore(volatile int* i, int value) { *i = value; } + static int CompareAndSwap(volatile int* i, int old_value, int new_value) { + return ::InterlockedCompareExchange(reinterpret_cast(i), + new_value, old_value); + } + // Pointer variants. + template + static T* AcquireLoadPtr(T* volatile* ptr) { + return *ptr; + } + template + static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) { + return static_cast(::InterlockedCompareExchangePointer( + reinterpret_cast(ptr), new_value, old_value)); + } +#else + static int Increment(volatile int* i) { return __sync_add_and_fetch(i, 1); } + static int Decrement(volatile int* i) { return __sync_sub_and_fetch(i, 1); } + static int AcquireLoad(volatile const int* i) { + return __atomic_load_n(i, __ATOMIC_ACQUIRE); + } + static void ReleaseStore(volatile int* i, int value) { + __atomic_store_n(i, value, __ATOMIC_RELEASE); + } + static int CompareAndSwap(volatile int* i, int old_value, int new_value) { + return __sync_val_compare_and_swap(i, old_value, new_value); + } + // Pointer variants. + template + static T* AcquireLoadPtr(T* volatile* ptr) { + return __atomic_load_n(ptr, __ATOMIC_ACQUIRE); + } + template + static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) { + return __sync_val_compare_and_swap(ptr, old_value, new_value); + } +#endif +}; + +} // namespace libwebrtc + +#endif // LIB_WEBRTC_ATOMICOPS_H_ diff --git a/windows/third_party/libwebrtc/include/base/fixed_size_function.h b/windows/third_party/libwebrtc/include/base/fixed_size_function.h new file mode 100644 index 0000000000..8cde1b5a50 --- /dev/null +++ b/windows/third_party/libwebrtc/include/base/fixed_size_function.h @@ -0,0 +1,301 @@ +// +// Copyright (c) 2014-2016 Pavel Medvedev. All rights reserved. +// +// Distributed under the MIT software license, see the accompanying +// file LICENSE + +#ifndef FIXED_SIZE_FUNCTION_HPP_INCLUDED +#define FIXED_SIZE_FUNCTION_HPP_INCLUDED + +#include +#include +#include +#include + +enum class construct_type { + none, + copy, + move, + copy_and_move, +}; + +namespace details { + +// V-table implementation +template +struct fixed_function_vtable_base { + Ret (*call)(void*, Args&&...) = nullptr; + void (*destroy)(void*) = nullptr; +}; + +template +struct fixed_function_vtable; + +template +struct fixed_function_vtable + : fixed_function_vtable_base {}; + +template +struct fixed_function_vtable + : fixed_function_vtable_base { + void (*copy)(const void*, void*) = nullptr; +}; + +template +struct fixed_function_vtable + : fixed_function_vtable_base { + void (*move)(void*, void*) = nullptr; +}; + +template +struct fixed_function_vtable + : fixed_function_vtable_base { + void (*copy)(const void*, void*) = nullptr; + void (*move)(void*, void*) = nullptr; +}; + +} // namespace details + +template +class fixed_size_function; + +template +class fixed_size_function { + public: + // Compile-time information + + using is_copyable = + std::integral_constant; + using is_movable = + std::integral_constant; + + using result_type = Ret; + + static const std::size_t arity = sizeof...(Args); + + template + struct argument { + static_assert(N < arity, "invalid argument index"); + using type = typename std::tuple_element>::type; + }; + + public: + template + fixed_size_function(fixed_size_function const&) = delete; + template + fixed_size_function(fixed_size_function&) = delete; + template + fixed_size_function(fixed_size_function&&) = delete; + template + fixed_size_function& operator=(fixed_size_function const&) = delete; + template + fixed_size_function& operator=(fixed_size_function&) = delete; + template + fixed_size_function& operator=(fixed_size_function&&) = delete; + template + void assign(fixed_size_function const&) = delete; + template + void assign(fixed_size_function&) = delete; + template + void assign(fixed_size_function&&) = delete; + + fixed_size_function() {} + + ~fixed_size_function() { reset(); } + + fixed_size_function(std::nullptr_t) {} + + fixed_size_function& operator=(std::nullptr_t) { + reset(); + return *this; + } + + fixed_size_function(fixed_size_function const& src) { copy(src); } + + fixed_size_function& operator=(fixed_size_function const& src) { + assign(src); + return *this; + } + + fixed_size_function(fixed_size_function& src) { copy(src); } + + fixed_size_function& operator=(fixed_size_function& src) { + assign(src); + return *this; + } + + fixed_size_function(fixed_size_function&& src) { + move(std::move(src), is_movable()); + } + + fixed_size_function& operator=(fixed_size_function&& src) { + assign(std::move(src)); + return *this; + } + + template + fixed_size_function(Functor&& f) { + create(std::forward(f)); + } + + template + fixed_size_function& operator=(Functor&& f) { + assign(std::forward(f)); + return *this; + } + + void assign(fixed_size_function const& src) { + reset(); + copy(src); + } + + void assign(fixed_size_function& src) { + reset(); + copy(src); + } + + void assign(fixed_size_function&& src) { + reset(); + move(std::move(src), is_movable()); + } + + template + void assign(Functor&& f) { + reset(); + create(std::forward(f)); + } + + void reset() { + auto destroy = vtable_.destroy; + if (destroy) { + vtable_ = vtable(); + destroy(&storage_); + } + } + + explicit operator bool() const { return vtable_.call != nullptr; } + + Ret operator()(Args... args) { + return vtable_.call ? vtable_.call(&storage_, std::forward(args)...) + : (Ret) nullptr; + } + + void swap(fixed_size_function& other) { + fixed_size_function tmp = std::move(other); + other = std::move(*this); + *this = std::move(tmp); + } + + friend void swap(fixed_size_function& lhs, fixed_size_function& rhs) { + lhs.swap(rhs); + } + + friend bool operator==(std::nullptr_t, fixed_size_function const& f) { + return !f; + } + + friend bool operator==(fixed_size_function const& f, std::nullptr_t) { + return !f; + } + + friend bool operator!=(std::nullptr_t, fixed_size_function const& f) { + return f; + } + + friend bool operator!=(fixed_size_function const& f, std::nullptr_t) { + return f; + } + + private: + template + void create(Functor&& f) { + using functor_type = typename std::decay::type; + static_assert(sizeof(functor_type) <= StorageSize, + "Functor must be smaller than storage buffer"); + + new (&storage_) functor_type(std::forward(f)); + + vtable_.call = &call_impl; + vtable_.destroy = &destroy_impl; + init_copy(is_copyable()); + init_move(is_movable()); + } + + void copy(fixed_size_function const& src) { + if (src.vtable_.copy) { + src.vtable_.copy(&src.storage_, &storage_); + vtable_ = src.vtable_; + } + } + + void move(fixed_size_function&& src, std::true_type movable) { + if (src.vtable_.move) { + src.vtable_.move(&src.storage_, &storage_); + vtable_ = src.vtable_; + src.reset(); + } + } + + void move(fixed_size_function const& src, std::false_type movable) { + copy(src); + } + + private: + template + static Ret call_impl(void* functor, Args&&... args) { + return (*static_cast(functor))(std::forward(args)...); + } + + template + static void destroy_impl(void* functor) { + static_cast(functor)->~Functor(); + } + + template + static void copy_impl(void const* functor, void* dest) { + new (dest) Functor(*static_cast(functor)); + } + + template + static void move_impl(void* functor, void* dest) { + new (dest) Functor(std::move(*static_cast(functor))); + } + + template + void init_copy(std::true_type /*copyable*/) { + vtable_.copy = ©_impl; + } + + template + void init_copy(std::false_type /*copyable*/) {} + + template + void init_move(std::true_type /*movable*/) { + vtable_.move = &move_impl; + } + + template + void init_move(std::false_type /*movable*/) {} + + private: + using vtable = + details::fixed_function_vtable; + static const size_t StorageSize = MaxSize - sizeof(vtable); + using storage = typename std::aligned_storage::type; + + vtable vtable_; + storage storage_; +}; + +#endif // FIXED_SIZE_FUNCTION_HPP_INCLUDED \ No newline at end of file diff --git a/windows/third_party/libwebrtc/include/base/inlined_vector.h b/windows/third_party/libwebrtc/include/base/inlined_vector.h new file mode 100644 index 0000000000..033ff5c3b0 --- /dev/null +++ b/windows/third_party/libwebrtc/include/base/inlined_vector.h @@ -0,0 +1,725 @@ +// Customise the behaviour of inlined_vector by defining these before including it: +// - #define BSP_INLINED_VECTOR_THROWS to get runtime_error +// - #define BSP_INLINED_VECTOR_LOG_ERROR(message) to log errors + +#ifndef BSP_INLINED_VECTOR_H +#define BSP_INLINED_VECTOR_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BSP_INLINED_VECTOR_THROWS +#include +#endif + +#ifdef WIN32 +#pragma warning(disable : 4172) +#endif + +namespace bsp { +namespace detail { + template class static_vector { + static_assert(Capacity > 0, "Capacity is <= 0!"); + + public: + using value_type = T; + using iterator = value_type*; + using const_iterator = const value_type*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = std::size_t; + + public: + static_vector() = default; + + static_vector(size_type count, const T& value = T()){ + size_ = count; + for(size_type i = 0; i < size_; ++i) { + new (data_+i) T(value); + } + } + + static_vector(const static_vector& other){ + size_ = other.size_; + for(size_type i = 0; i < size_; ++i) { + new (data_+i) T(other[i]); + } + } + + static_vector(static_vector&& other){ + size_ = other.size_; + for(size_type i = 0; i < size_; ++i) { + new (data_+i) T(std::move(other[i])); + } + } + + static_vector& operator=(const static_vector& other){ + destroy_all(); + size_ = other.size_; + for(size_type i = 0; i < size_; ++i) { + new (data_+i) T(other[i]); + } + return *this; + } + + static_vector& operator=(static_vector&& other){ + destroy_all(); + size_ = other.size_; + for(size_type i = 0; i < size_; ++i) { + new (data_+i) T(std::move(other[i])); + } + return *this; + } + + ~static_vector(){ + destroy_all(); + } + + inline size_type size() const { return size_; } + + constexpr static inline size_type max_size() { return Capacity; } + + template + void push_back(U&& value) { +#ifdef BSP_INLINED_VECTOR_THROWS + if( size_ >= max_size() ) throw std::bad_alloc{}; +#endif + new (data_+size_) T(std::forward(value)); + ++size_; + } + + template void emplace_back(Args&&... args) { +#ifdef BSP_INLINED_VECTOR_THROWS + if( size_ >= max_size() ) throw std::bad_alloc{}; +#endif + new (data_+size_) T(std::forward(args)...); + ++size_; + } + + T& operator[](size_type i){ + return *launder(data_ + i); + } + + const T& operator[](size_type i) const { + return *launder(data_ + i); + } + + iterator begin() { return launder(data_); } + iterator end() { return begin() + size_; } + + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } + + const_iterator begin() const { return launder(data_); } + const_iterator end() const { return begin() + size_; } + + reverse_iterator rbegin() { return rend() - size_; } + reverse_iterator rend() { return std::reverse_iterator(begin()); } + + const_reverse_iterator rbegin() const { return rend() - size_; } + const_reverse_iterator rend() const { return std::reverse_iterator(begin()); } + + template void emplace_into(Container& container){ + assert(container.size() == 0); + container.resize(size_); + std::move(begin(), end(), container.begin()); + destroy_all(); + } + + void fill_n(size_type count, const T& value) { + destroy_all(); +#ifdef BSP_INLINED_VECTOR_THROWS + if( count > max_size() ) throw std::bad_alloc{}; +#endif + for(size_type i = 0; i < count; ++i) { + new (data_+i) T(value); + } + size_ = count; + } + + protected: + using raw_type = typename std::aligned_storage::type; + + raw_type data_[Capacity]; + size_type size_ = 0; + + protected: + T* launder(raw_type* rt){ + return reinterpret_cast(rt); + } + + const T* launder(const raw_type* rt) const { + return reinterpret_cast(rt); + } + + inline void destroy(raw_type* rt){ + launder(rt)->~T(); + } + + void destroy_all(){ + for(size_type i = 0; i < size_; ++i) { + destroy(data_+i); + } + size_ = 0; + } + }; + + template struct is_iterator : std::false_type {}; + template struct is_iterator::iterator_category>::value || + std::is_same::iterator_category>::value>::type>: std::true_type {}; +} + +// An inlined_vector is a fixed-size array with a vector-like interface +// that can optionally grow beyond its capacity and become a std::vector. +template +class inlined_vector { + static_assert(Capacity > 0, "Capacity is <= 0!"); + +public: + using value_type = T; + using reference = T&; + using const_reference = const T&; + using iterator = value_type*; + using const_iterator = const value_type*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = std::size_t; + +public: + inlined_vector() = default; + virtual ~inlined_vector() = default; + + inlined_vector(size_type count, const T& value = T()):data_internal_(std::min(count, max_size()), value){ + if (count > max_size()) { + size_ = max_size(); + error("inlined_vector(count, value) got too many elements"); + } + else { + size_ = count; + } + } + + template + inlined_vector(const inlined_vector& other) + : inlined_vector(other.begin(), other.size()) {} + + template + inlined_vector(inlined_vector&& other) + : inlined_vector(other.begin(), other.size()) {} + + template + inlined_vector(const Container& els) : inlined_vector(els.begin(), els.size()) {} + + inlined_vector(std::initializer_list els) : inlined_vector(els.begin(), els.size()) {} + + constexpr static inline size_type max_size() { return Capacity; } + + inline virtual bool can_expand() const { return false; } + + inline void clear() { size_ = 0; } + + inline size_type size() const { return size_; } + + inline bool empty() const { return size_ == 0; } + + inline bool full() const { return size_ >= max_size(); } + + inline virtual bool expanded() const { return false; } + + template + inline void push_back(U&& value) { + if (size_ >= max_size()) { + error("inlined_vector::push_back exceeded Capacity"); + } + else { + data_internal_.push_back(std::forward(value)); + size_++; + } + } + + template inline void emplace_back(Args&&... args) { + if (size_ >= max_size()) { + error("inlined_vector::emplace_back exceeded Capacity"); + } + else { + data_internal_.emplace_back(std::forward(args)...); + size_++; + } + } + + template void extend(const Container& other) { + for (auto v : other) { + push_back(std::move(v)); + } + } + + void extend(std::initializer_list other) { + for (auto v : other) { + push_back(std::move(v)); + } + } + + inline virtual void pop_back() { + if (!empty()) size_--; + } + + inline const_reference back() const { + if (!empty()) { + return *std::prev(end()); + } + return data_internal_[0]; + } + + inline reference back() { return const_cast(static_cast(this)->back()); } + + inline const_reference front() const { + if (!empty()) { + return *begin(); + } + return data_internal_[0]; + } + + inline reference front() { return const_cast(static_cast(this)->front()); } + + inline reference operator[](size_type i) { return element(i); } + + inline const_reference operator[](size_type i) const { return element(i); } + + inline const_reference at(size_type i) const { + if (i >= 0 && i < size_) { + return element(i); + } + else { +#ifdef BSP_INLINED_VECTOR_THROWS + throw std::out_of_range("inlined_vector::at"); +#else + return nullptr; +#endif + } + } + + inline reference at(size_type i) { + return const_cast(static_cast(this)->at(i)); + } + + virtual iterator begin() { return data_internal_.begin(); } + iterator end() { return begin() + size_; } + + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } + + virtual const_iterator begin() const { return data_internal_.begin(); } + const_iterator end() const { return begin() + size_; } + + reverse_iterator rbegin() { return rend() - size_; } + virtual reverse_iterator rend() { return data_internal_.rend(); } + + const_reverse_iterator rbegin() const { return rend() - size_; } + virtual const_reverse_iterator rend() const { return data_internal_.rend(); } + + iterator erase(const_iterator it) { + validate_iterator(it); + + if (it == end() || empty()) { + error("inlined_vector::erase it == end or container is empty"); + return end(); + } + + size_type i = iterator_index(it); + if (i == size_) { + error("inlined_vector::insert invalid iterator"); + return end(); + } + for (size_type j = i; j < size_ - 1; j++) { + element(j) = std::move(element(j + 1)); + } + size_--; + return begin() + i; + } + + iterator insert(iterator it, const_reference value) { + validate_iterator(it); + + if (full()) { + error("inlined_vector::insert exceeded Capacity"); + return end(); + } + + if (it == end()) { + push_back(value); + return std::prev(end(), 1); + } + else { + // Insert at i and push everything back + size_type i = iterator_index(it); + if (i == size_) { + error("inlined_vector::insert invalid iterator"); + return end(); + } + for (size_type j = size_; j > i; j--) { + element(j) = std::move(element(j - 1)); + } + element(i) = value; + size_++; + return std::next(begin(), i); + } + } + + inline bool contains(const_reference value) const { + auto begin_ = begin(); + auto end_ = end(); + return std::find(begin_, end_, value) != end_; + } + +protected: + using array_type = detail::static_vector; + + array_type data_internal_; + size_type size_ = 0; + +protected: + // Helper constructor + template::value>::type> + inlined_vector(Iter begin_, std::size_t size) { + if (size > max_size()) { + error("inlined_vector() too many elements"); + size_ = max_size(); + } + else { + size_ = size; + } + + auto end_ = std::next(begin_, size_); + for (auto it = begin_; it != end_; ++it){ + data_internal_.emplace_back(std::move(*it)); + } + } + + // Helper constructor for sub-class + inlined_vector(array_type&& array, std::size_t size) + : data_internal_(std::move(array)), size_(size) {} + + inline reference element(size_type index) { return *std::next(begin(), index); } + + inline const_reference element(size_type index) const { return *std::next(begin(), index); } + + size_type iterator_index(const_iterator it) const { + auto nit = begin(); + for (size_type i = 0; i < size_; i++) { + if (nit == it) + return i; + nit++; + } + return size_; + } + + inline void validate_iterator(const_iterator it) { +#ifndef NDEBUG + if (it < begin() || it > end()) { + error("inlined_vector::validate_iterator invalid iterator"); + } +#endif + } + + void error(const char* message) const { +#ifdef BSP_INLINED_VECTOR_LOG_ERROR + BSP_INLINED_VECTOR_LOG_ERROR(message); +#endif + +#ifdef BSP_INLINED_VECTOR_THROWS + throw std::runtime_error(message); +#endif + } + + template + friend std::ostream& operator<<(std::ostream& out, const inlined_vector& vector); +}; + +template +class inlined_vector : public inlined_vector { + static_assert(Capacity > 0, "Capacity is <= 0!"); + +public: + using base_t = inlined_vector; + using typename base_t::value_type; + using typename base_t::reference; + using typename base_t::const_reference; + using typename base_t::iterator; + using typename base_t::const_iterator; + using typename base_t::reverse_iterator; + using typename base_t::const_reverse_iterator; + using typename base_t::size_type; + using base_t::cbegin; + using base_t::element; + using base_t::empty; + using base_t::end; + using base_t::error; + using base_t::max_size; + using base_t::rbegin; + using base_t::data_internal_; + using base_t::size_; + +public: + inlined_vector() = default; + + inlined_vector(size_type count, const T& value = T()){ + size_ = count; + if (size_ <= max_size()){ + data_internal_.fill_n(count, value); + } + else { + data_external_.resize(size_); + std::fill_n(data_external_.begin(), count, value); + inlined_ = false; + } + } + + template + inlined_vector(const inlined_vector& other) + : inlined_vector(other.begin(), other.end(), other.size()) {} + + inlined_vector(inlined_vector&& other) + : base_t(std::move(other.data_internal_), other.size_), + data_external_(std::move(other.data_external_)), + inlined_(other.inlined_) { + other.inlined_ = true; + other.size_ = 0; + } + + template + inlined_vector(const Container& els) : inlined_vector(els.begin(), els.end(), els.size()) {} + + inlined_vector(std::initializer_list els) + : inlined_vector(els.begin(), els.end(), els.size()) {} + + inlined_vector(const inlined_vector& other) + : inlined_vector(other.begin(), other.end(), other.size()) {} + + inlined_vector& operator=(inlined_vector&& other) { + inlined_ = other.inlined_; + size_ = other.size_; + data_internal_ = std::move(other.data_internal_); + data_external_ = std::move(other.data_external_); + other.inlined_ = true; + other.size_ = 0; + return *this; + } + + inlined_vector& operator=(const inlined_vector& other) { + inlined_ = other.inlined_; + size_ = other.size_; + data_internal_ = other.data_internal_; + data_external_ = other.data_external_; + return *this; + } + + template void extend(const Container& other) { + for (auto v : other) { + push_back(std::move(v)); + } + } + + void extend(std::initializer_list other) { + for (auto v : other) { + push_back(std::move(v)); + } + } + + inline virtual bool can_expand() const override final { return true; } + + inline void clear() { + if (!inlined_) { + inlined_ = false; + data_external_.clear(); + } + base_t::clear(); + } + + inline bool expanded() const final override { return !inlined_; } + + template + inline void push_back(U&& value) { + if (inlined_ && size_ >= max_size()) { + grow_to_external_storage(); + } + + if (inlined_) { + base_t::push_back(std::forward(value)); + } + else { + data_external_.push_back(std::forward(value)); + size_++; + } + } + + template inline void emplace_back(Args&&... args) { + if (inlined_ && size_ >= max_size()) { + grow_to_external_storage(); + } + + if (inlined_) { + base_t::emplace_back(std::forward(args)...); + } + else { + data_external_.emplace_back(std::forward(args)...); + size_++; + } + } + + inline void pop_back() override final { + if (!empty()){ + if (inlined_) data_external_.pop_back(); + size_--; + } + } + + iterator begin() override final { + return inlined_ ? data_internal_.begin() : unwrap(data_external_.begin()); + } + const_iterator begin() const override final { + return inlined_ ? data_internal_.begin() : unwrap(data_external_.begin()); + } + reverse_iterator rend() override final { + return inlined_ ? data_internal_.rend() : unwrap(data_external_.rend()); + } + const_reverse_iterator rend() const override final { + return inlined_ ? data_internal_.rend() : unwrap(data_external_.rend()); + } + + iterator erase(const_iterator it) { + base_t::validate_iterator(it); + + if (it == end() || empty()) { + error("inlined_vector::erase it == end or container is empty"); + } + + if (inlined_) { + size_type i = base_t::iterator_index(it); + if (i == size_) { + error("inlined_vector::erase invalid iterator"); + return end(); + } + for (size_type j = i; j < size_ - 1; j++) { + element(j) = std::move(element(j + 1)); + } + size_--; + return begin() + i; + } + else { + size_--; + auto vit = std::next(data_external_.cbegin(), std::distance(cbegin(), it)); + return unwrap(data_external_.erase(vit)); + } + } + + iterator insert(iterator it, const_reference value) { + base_t::validate_iterator(it); + + if (inlined_ && size_ < max_size()) { + return base_t::insert(it, value); + } + else if (inlined_ && size_ >= max_size()) { + size_type index_ = base_t::iterator_index(it); + grow_to_external_storage(); + it = std::next(begin(), index_); + } + + if (it == end()) { + push_back(value); + return end(); + } + else { + size_++; + // NB: dataVector may not have a T* iterator + auto vit = std::next(data_external_.begin(), std::distance(begin(), it)); + return unwrap(data_external_.insert(vit, value)); + } + } + +protected: + std::vector data_external_; + bool inlined_ = true; + +protected: + // Helper constructor + template inlined_vector(Iter begin_, Iter end_, size_type size) { + size_ = size; + if (size_ <= max_size()) { + for (auto it = begin_; it != end_; ++it){ + data_internal_.emplace_back(std::move(*it)); + } + } + else { + data_external_.resize(size_); + std::move(begin_, end_, data_external_.begin()); + inlined_ = false; + } + } + + // Sometimes std::vector::iterator isn't a T* (e.g., in clang/libcxx) + // so we need to unwrap the iterator + inline iterator unwrap(typename std::vector::iterator it) const { return &*it; } + inline const_iterator unwrap(typename std::vector::const_iterator it) const { return &*it; } + inline reverse_iterator unwrap(typename std::vector::reverse_iterator it) const { + return reverse_iterator(&*it); + } + inline const_reverse_iterator unwrap(typename std::vector::const_reverse_iterator it) const { + return const_reverse_iterator(&*it); + } + + void grow_to_external_storage() { + assert(inlined_); + data_internal_.emplace_into(data_external_); + inlined_ = false; + } + + template + friend std::ostream& operator<<(std::ostream& out, const inlined_vector& vector); +}; + +template +inline std::ostream& operator<<(std::ostream& out, const inlined_vector& vector) { + out << "inlined_vector "; + out << "(inlined): ["; + if (vector.empty()) + out << "]"; + else { + for (auto it = vector.begin(); it != vector.end(); ++it) { + if (std::next(it) != vector.end()) + out << *it << ", "; + else + out << *it << "]"; + } + } + return out; +} + +template +inline std::ostream& operator<<(std::ostream& out, const inlined_vector& vector) { + out << "inlined_vector "; + if (vector.inlined_) + out << "(inlined): ["; + else + out << "(external): ["; + if (vector.empty()) + out << "]"; + else { + for (auto it = vector.begin(); it != vector.end(); ++it) { + if (std::next(it) != vector.end()) + out << *it << ", "; + else + out << *it << "]"; + } + } + return out; +} +} // namespace bsp + +#endif diff --git a/windows/third_party/libwebrtc/include/base/refcount.h b/windows/third_party/libwebrtc/include/base/refcount.h new file mode 100644 index 0000000000..6e3360e87b --- /dev/null +++ b/windows/third_party/libwebrtc/include/base/refcount.h @@ -0,0 +1,29 @@ +/* + * Copyright 2011 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef LIB_WEBRTC_REFCOUNT_H_ +#define LIB_WEBRTC_REFCOUNT_H_ + +#include "refcountedobject.h" + +namespace libwebrtc { + +// Reference count interface. +class RefCountInterface { + public: + virtual int AddRef() const = 0; + virtual int Release() const = 0; + + protected: + virtual ~RefCountInterface() {} +}; + +} // namespace libwebrtc + +#endif // WEBRTC_BASE_REFCOUNT_H_ diff --git a/windows/third_party/libwebrtc/include/base/refcountedobject.h b/windows/third_party/libwebrtc/include/base/refcountedobject.h new file mode 100644 index 0000000000..50feef73ff --- /dev/null +++ b/windows/third_party/libwebrtc/include/base/refcountedobject.h @@ -0,0 +1,61 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef LIB_WEBRTC_REFCOUNTEDOBJECT_H_ +#define LIB_WEBRTC_REFCOUNTEDOBJECT_H_ + +#include + +#include "atomicops.h" + +namespace libwebrtc { + +template +class RefCountedObject : public T { + public: + RefCountedObject() {} + + template + explicit RefCountedObject(P0&& p0) : T(std::forward(p0)) {} + + template + RefCountedObject(P0&& p0, P1&& p1, Args&&... args) + : T(std::forward(p0), + std::forward(p1), + std::forward(args)...) {} + + virtual int AddRef() const { return AtomicOps::Increment(&ref_count_); } + + virtual int Release() const { + int count = AtomicOps::Decrement(&ref_count_); + if (!count) { + delete this; + } + return count; + } + + // Return whether the reference count is one. If the reference count is used + // in the conventional way, a reference count of 1 implies that the current + // thread owns the reference and no other thread shares it. This call + // performs the test for a reference count of one, and performs the memory + // barrier needed for the owning thread to act on the object, knowing that it + // has exclusive access to the object. + virtual bool HasOneRef() const { + return AtomicOps::AcquireLoad(&ref_count_) == 1; + } + + protected: + virtual ~RefCountedObject() {} + + mutable volatile int ref_count_ = 0; +}; + +} // namespace libwebrtc + +#endif // LIB_WEBRTC_REFCOUNTEDOBJECT_H_ diff --git a/windows/third_party/libwebrtc/include/base/scoped_ref_ptr.h b/windows/third_party/libwebrtc/include/base/scoped_ref_ptr.h new file mode 100644 index 0000000000..1a134b61bb --- /dev/null +++ b/windows/third_party/libwebrtc/include/base/scoped_ref_ptr.h @@ -0,0 +1,161 @@ +/* + * Copyright 2011 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Originally these classes are from Chromium. +// http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h?view=markup + +// +// A smart pointer class for reference counted objects. Use this class instead +// of calling AddRef and Release manually on a reference counted object to +// avoid common memory leaks caused by forgetting to Release an object +// reference. Sample usage: +// +// class MyFoo : public RefCounted { +// ... +// }; +// +// void some_function() { +// scoped_refptr foo = new MyFoo(); +// foo->Method(param); +// // |foo| is released when this function returns +// } +// +// void some_other_function() { +// scoped_refptr foo = new MyFoo(); +// ... +// foo = NULL; // explicitly releases |foo| +// ... +// if (foo) +// foo->Method(param); +// } +// +// The above examples show how scoped_refptr acts like a pointer to T. +// Given two scoped_refptr classes, it is also possible to exchange +// references between the two objects, like so: +// +// { +// scoped_refptr a = new MyFoo(); +// scoped_refptr b; +// +// b.swap(a); +// // now, |b| references the MyFoo object, and |a| references NULL. +// } +// +// To make both |a| and |b| in the above example reference the same MyFoo +// object, simply use the assignment operator: +// +// { +// scoped_refptr a = new MyFoo(); +// scoped_refptr b; +// +// b = a; +// // now, |a| and |b| each own a reference to the same MyFoo object. +// } +// + +#ifndef LIB_WEBRTC_SCOPED_REF_PTR_H_ +#define LIB_WEBRTC_SCOPED_REF_PTR_H_ + +#include + +namespace libwebrtc { + +template +class scoped_refptr { + public: + scoped_refptr() : ptr_(NULL) {} + + scoped_refptr(T* p) : ptr_(p) { + if (ptr_) + ptr_->AddRef(); + } + + scoped_refptr(const scoped_refptr& r) : ptr_(r.ptr_) { + if (ptr_) + ptr_->AddRef(); + } + + template + scoped_refptr(const scoped_refptr& r) : ptr_(r.get()) { + if (ptr_) + ptr_->AddRef(); + } + + // Move constructors. + scoped_refptr(scoped_refptr&& r) : ptr_(r.release()) {} + + template + scoped_refptr(scoped_refptr&& r) : ptr_(r.release()) {} + + ~scoped_refptr() { + if (ptr_) + ptr_->Release(); + } + + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + T* operator->() const { return ptr_; } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + T* release() { + T* retVal = ptr_; + ptr_ = NULL; + return retVal; + } + + scoped_refptr& operator=(T* p) { + // AddRef first so that self assignment should work + if (p) + p->AddRef(); + if (ptr_) + ptr_->Release(); + ptr_ = p; + return *this; + } + + scoped_refptr& operator=(const scoped_refptr& r) { + return *this = r.ptr_; + } + + template + scoped_refptr& operator=(const scoped_refptr& r) { + return *this = r.get(); + } + + scoped_refptr& operator=(scoped_refptr&& r) { + scoped_refptr(std::move(r)).swap(*this); + return *this; + } + + template + scoped_refptr& operator=(scoped_refptr&& r) { + scoped_refptr(std::move(r)).swap(*this); + return *this; + } + + void swap(T** pp) { + T* p = ptr_; + ptr_ = *pp; + *pp = p; + } + + void swap(scoped_refptr& r) { swap(&r.ptr_); } + + protected: + T* ptr_; +}; + +} // namespace libwebrtc + +#endif // LIB_WEBRTC_SCOPED_REF_PTR_H_ diff --git a/windows/third_party/libwebrtc/include/libwebrtc.h b/windows/third_party/libwebrtc/include/libwebrtc.h new file mode 100644 index 0000000000..08cc4a50c8 --- /dev/null +++ b/windows/third_party/libwebrtc/include/libwebrtc.h @@ -0,0 +1,22 @@ +#ifndef LIB_WEBRTC_HXX +#define LIB_WEBRTC_HXX + +#include "rtc_types.h" +#include "rtc_peerconnection_factory.h" + +namespace libwebrtc { + +class LibWebRTC { + public: + LIB_WEBRTC_API static bool Initialize(); + + LIB_WEBRTC_API static scoped_refptr< + RTCPeerConnectionFactory> + CreateRTCPeerConnectionFactory(); + + LIB_WEBRTC_API static void Terminate(); +}; + +}; // namespace libwebrtc + +#endif //LIB_WEBRTC_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_audio_device.h b/windows/third_party/libwebrtc/include/rtc_audio_device.h new file mode 100644 index 0000000000..ec257ff301 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_audio_device.h @@ -0,0 +1,39 @@ +#ifndef LIB_WEBRTC_RTC_AUDIO_DEVICE_HXX +#define LIB_WEBRTC_RTC_AUDIO_DEVICE_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCAudioDevice : public RefCountInterface { + public: + static const int kAdmMaxDeviceNameSize = 128; + static const int kAdmMaxFileNameSize = 512; + static const int kAdmMaxGuidSize = 128; + + public: + // Device enumeration + virtual int16_t PlayoutDevices() = 0; + + virtual int16_t RecordingDevices() = 0; + + virtual int32_t PlayoutDeviceName(uint16_t index, + char name[kAdmMaxDeviceNameSize], + char guid[kAdmMaxGuidSize]) = 0; + + virtual int32_t RecordingDeviceName(uint16_t index, + char name[kAdmMaxDeviceNameSize], + char guid[kAdmMaxGuidSize]) = 0; + + // Device selection + virtual int32_t SetPlayoutDevice(uint16_t index) = 0; + + virtual int32_t SetRecordingDevice(uint16_t index) = 0; + + protected: + virtual ~RTCAudioDevice() {} +}; + +}; // namespace libwebrtc + +#endif //LIB_WEBRTC_RTC_AUDIO_DEVICE_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_audio_frame.h b/windows/third_party/libwebrtc/include/rtc_audio_frame.h new file mode 100644 index 0000000000..9b9256d53d --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_audio_frame.h @@ -0,0 +1,52 @@ +#ifndef AUDIO_FRAME_HXX +#define AUDIO_FRAME_HXX + +#include "media_manager_types.h" + +namespace b2bua { + +class AudioFrame +{ +public: + MEDIA_MANAGER_API static AudioFrame* Create(); + 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); + + virtual void Release() = 0; + +public: + virtual void UpdateFrame( + int id, + uint32_t timestamp, + const int16_t* data, + size_t samples_per_channel, + int sample_rate_hz, + size_t num_channels = 1) = 0; + + virtual void CopyFrom(const AudioFrame& src) = 0; + + virtual void Add(const AudioFrame& frame_to_add) = 0; + + virtual void Mute() = 0; + + virtual const int16_t *data() = 0; + + virtual size_t samples_per_channel() = 0; + + virtual int sample_rate_hz() = 0; + + virtual size_t num_channels() = 0; + + virtual uint32_t timestamp() = 0; + + virtual int id() = 0; +}; + +};//namespace b2bua + +#endif diff --git a/windows/third_party/libwebrtc/include/rtc_audio_source.h b/windows/third_party/libwebrtc/include/rtc_audio_source.h new file mode 100644 index 0000000000..1011783c00 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_audio_source.h @@ -0,0 +1,15 @@ +#ifndef LIB_WEBRTC_RTC_AUDIO_SOURCE_HXX +#define LIB_WEBRTC_RTC_AUDIO_SOURCE_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCAudioSource : public RefCountInterface { + protected: + virtual ~RTCAudioSource() {} +}; + +}; // namespace libwebrtc + +#endif //LIB_WEBRTC_RTC_AUDIO_TRACK_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_audio_track.h b/windows/third_party/libwebrtc/include/rtc_audio_track.h new file mode 100644 index 0000000000..ddd040c1d5 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_audio_track.h @@ -0,0 +1,16 @@ +#ifndef LIB_WEBRTC_RTC_AUDIO_TRACK_HXX +#define LIB_WEBRTC_RTC_AUDIO_TRACK_HXX + +#include "rtc_types.h" +#include "rtc_media_track.h" + +namespace libwebrtc { + +class RTCAudioTrack : public RTCMediaTrack { + protected: + virtual ~RTCAudioTrack() {} +}; + +}; // namespace libwebrtc + +#endif //LIB_WEBRTC_RTC_AUDIO_TRACK_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_data_channel.h b/windows/third_party/libwebrtc/include/rtc_data_channel.h new file mode 100644 index 0000000000..854280c945 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_data_channel.h @@ -0,0 +1,57 @@ +#ifndef LIB_WEBRTC_RTC_DATA_CHANNEL_HXX +#define LIB_WEBRTC_RTC_DATA_CHANNEL_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +enum RTCDataChannelState { + RTCDataChannelConnecting, + RTCDataChannelOpen, + RTCDataChannelClosing, + RTCDataChannelClosed, +}; + +struct RTCDataChannelInit { + bool ordered = true; + bool reliable = true; + int maxRetransmitTime = -1; + int maxRetransmits = -1; + char protocol[kMaxStringLength] = {"sctp"}; // sctp | quic + bool negotiated = false; + int id = 0; +}; + +class RTCDataChannelObserver { + public: + virtual void OnStateChange(RTCDataChannelState state) = 0; + + virtual void OnMessage(const char* buffer, int length, bool binary) = 0; + + protected: + virtual ~RTCDataChannelObserver() = default; +}; + +class RTCDataChannel : public RefCountInterface { + public: + virtual void Send(const char *data, int length, bool binary = false) = 0; + + virtual void Close() = 0; + + virtual void RegisterObserver(RTCDataChannelObserver* observer) = 0; + + virtual void UnregisterObserver() = 0; + + virtual const char* label() const = 0; + + virtual int id() const = 0; + + virtual RTCDataChannelState state() = 0; + + protected: + virtual ~RTCDataChannel() {} +}; + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_DATA_CHANNEL_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_ice_candidate.h b/windows/third_party/libwebrtc/include/rtc_ice_candidate.h new file mode 100644 index 0000000000..d27273c407 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_ice_candidate.h @@ -0,0 +1,30 @@ +#ifndef LIB_WEBRTC_RTC_ICE_CANDIDATE_HXX +#define LIB_WEBRTC_RTC_ICE_CANDIDATE_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCIceCandidate : public RefCountInterface { + public: + virtual const char* candidate() const = 0; + + virtual const char* sdp_mid() const = 0; + + virtual int sdp_mline_index() const = 0; + + virtual bool ToString(char* buffer, int length) = 0; + + protected: + virtual ~RTCIceCandidate() {} +}; + +LIB_WEBRTC_API scoped_refptr CreateRTCIceCandidate( + const char* sdp, + const char* sdp_mid, + int sdp_mline_index, + SdpParseError* error); + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_ICE_CANDIDATE_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_media_stream.h b/windows/third_party/libwebrtc/include/rtc_media_stream.h new file mode 100644 index 0000000000..fadd86796a --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_media_stream.h @@ -0,0 +1,46 @@ +#ifndef LIB_WEBRTC_RTC_MEDIA_STREAM_HXX +#define LIB_WEBRTC_RTC_MEDIA_STREAM_HXX + +#include "rtc_types.h" +#include "rtc_audio_track.h" +#include "rtc_video_track.h" + +namespace libwebrtc { + +typedef Vector> AudioTrackVector; +typedef Vector> VideoTrackVector; + +class RTCMediaStream : public RefCountInterface { + public: + virtual bool AddTrack(scoped_refptr track) = 0; + + virtual bool AddTrack(scoped_refptr track) = 0; + + virtual bool RemoveTrack(scoped_refptr track) = 0; + + virtual bool RemoveTrack(scoped_refptr track) = 0; + + /*获取所有音频轨道*/ + virtual AudioTrackVector GetAudioTracks() = 0; + + /*获取所有视频轨道*/ + virtual VideoTrackVector GetVideoTracks() = 0; + + virtual scoped_refptr FindAudioTrack( + const char* track_id) = 0; + + virtual scoped_refptr FindVideoTrack( + const char* track_id) = 0; + + /*media stream label 对应sdp msid 前缀*/ + virtual const char* label() = 0; + + protected: + ~RTCMediaStream() {} +}; + +typedef Vector> MediaStreamVector; + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_MEDIA_STREAM_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_media_track.h b/windows/third_party/libwebrtc/include/rtc_media_track.h new file mode 100644 index 0000000000..b722ab7684 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_media_track.h @@ -0,0 +1,28 @@ +#ifndef LIB_WEBRTC_RTC_MEDIA_TRACK_HXX +#define LIB_WEBRTC_RTC_MEDIA_TRACK_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +/*Media Track interface*/ +class RTCMediaTrack : public RefCountInterface { + public: + /*track type: audio/video*/ + virtual const char* kind() const = 0; + + /*track id*/ + virtual const char* id() const = 0; + + virtual bool enabled() const = 0; + + /*mute track*/ + virtual bool set_enabled(bool enable) = 0; + + protected: + ~RTCMediaTrack() {} +}; + +}; // namespace libwebrtc + +#endif //LIB_WEBRTC_RTC_MEDIA_TRACK_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_mediaconstraints.h b/windows/third_party/libwebrtc/include/rtc_mediaconstraints.h new file mode 100644 index 0000000000..2e215d40ae --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_mediaconstraints.h @@ -0,0 +1,47 @@ +#ifndef LIB_WEBRTC_RTC_MEDIA_CONSTRAINTS_HXX +#define LIB_WEBRTC_RTC_MEDIA_CONSTRAINTS_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCMediaConstraints : public RefCountInterface { + public: + /** Constraint keys for media sources. */ + LIB_WEBRTC_API static const char* kMinAspectRatio; + LIB_WEBRTC_API static const char* kMaxAspectRatio; + LIB_WEBRTC_API static const char* kMaxWidth; + LIB_WEBRTC_API static const char* kMinWidth; + LIB_WEBRTC_API static const char* kMaxHeight; + LIB_WEBRTC_API static const char* kMinHeight; + LIB_WEBRTC_API static const char* kMaxFrameRate; + LIB_WEBRTC_API static const char* kMinFrameRate; + /** The value for this key should be a base64 encoded string containing + * the data from the serialized configuration proto. + */ + LIB_WEBRTC_API static const char* kAudioNetworkAdaptorConfig; + + /** Constraint keys for generating offers and answers. */ + LIB_WEBRTC_API static const char* kIceRestart; + LIB_WEBRTC_API static const char* kOfferToReceiveAudio; + LIB_WEBRTC_API static const char* kOfferToReceiveVideo; + LIB_WEBRTC_API static const char* kVoiceActivityDetection; + + /** Constraint values for Boolean parameters. */ + LIB_WEBRTC_API static const char* kValueTrue; + LIB_WEBRTC_API static const char* kValueFalse; + + public: + LIB_WEBRTC_API static scoped_refptr Create(); + + virtual void AddMandatoryConstraint(const char* key, const char* value) = 0; + + virtual void AddOptionalConstraint(const char* key, const char* value) = 0; + + protected: + virtual ~RTCMediaConstraints() {} +}; + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_MEDIA_CONSTRAINTS_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_peerconnection.h b/windows/third_party/libwebrtc/include/rtc_peerconnection.h new file mode 100644 index 0000000000..dc61cbde34 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_peerconnection.h @@ -0,0 +1,193 @@ +#ifndef LIB_WEBRTC_RTC_PEERCONNECTION_HXX +#define LIB_WEBRTC_RTC_PEERCONNECTION_HXX + +#include "rtc_types.h" +#include "rtc_audio_track.h" +#include "rtc_data_channel.h" +#include "rtc_ice_candidate.h" +#include "rtc_media_stream.h" +#include "rtc_mediaconstraints.h" +#include "rtc_session_description.h" +#include "rtc_video_source.h" +#include "rtc_video_track.h" + +#include + +namespace libwebrtc { + +enum SessionDescriptionErrorType { + kPeerConnectionInitFailed = 0, + kCreatePeerConnectionFailed, + kSDPParseFailed, +}; + +enum RTCSignalingState { + RTCSignalingStateStable, + RTCSignalingStateHaveLocalOffer, + RTCSignalingStateHaveRemoteOffer, + RTCSignalingStateHaveLocalPrAnswer, + RTCSignalingStateHaveRemotePrAnswer, + RTCSignalingStateClosed +}; + +enum RTCIceGatheringState { + RTCIceGatheringStateNew, + RTCIceGatheringStateGathering, + RTCIceGatheringStateComplete +}; + +enum RTCIceConnectionState { + RTCIceConnectionStateNew, + RTCIceConnectionStateChecking, + RTCIceConnectionStateCompleted, + RTCIceConnectionStateConnected, + RTCIceConnectionStateFailed, + RTCIceConnectionStateDisconnected, + RTCIceConnectionStateClosed, + RTCIceConnectionStateMax, +}; + +class MediaTrackStatistics { + public: + MediaTrackStatistics() {} + int64_t bytes_received = 0; + int64_t bytes_sent = 0; + int packets_lost = 0; + int packets_received = 0; + int packets_sent = 0; + int frame_rate_sent = 0; + int frame_rate_received = 0; + uint32_t rtt = 0; + + int64_t ssrc = 0; + char msid[kMaxStringLength]; + char kind[kShortStringLength]; + char direction[kShortStringLength]; + + public: + MediaTrackStatistics(const MediaTrackStatistics* stats) { copy(*stats); } + + MediaTrackStatistics& operator=(const MediaTrackStatistics& rhs) { + if (&rhs == this) + return *this; + return copy(rhs); + } + + MediaTrackStatistics& copy(const MediaTrackStatistics& rhs) { + strncpy(direction, rhs.direction, sizeof(direction)); + strncpy(kind, rhs.kind, sizeof(kind)); + packets_sent = rhs.packets_sent; + packets_received = rhs.packets_received; + packets_lost = rhs.packets_lost; + bytes_sent = rhs.bytes_sent; + bytes_received = rhs.bytes_received; + frame_rate_sent = rhs.frame_rate_sent; + frame_rate_received = rhs.frame_rate_received; + ssrc = rhs.ssrc; + rtt = rhs.rtt; + strncpy(msid, rhs.msid, sizeof(msid)); + return *this; + } +}; + +class TrackStatsObserver : public RefCountInterface { + public: + virtual void OnComplete(const MediaTrackStatistics& reports) = 0; + + protected: + ~TrackStatsObserver() {} +}; + +typedef fixed_size_function + OnSdpCreateSuccess; + +typedef fixed_size_function OnSdpCreateFailure; + +typedef fixed_size_function OnSetSdpSuccess; + +typedef fixed_size_function OnSetSdpFailure; + +class RTCPeerConnectionObserver { + public: + virtual void OnSignalingState(RTCSignalingState state) = 0; + + virtual void OnIceGatheringState(RTCIceGatheringState state) = 0; + + virtual void OnIceConnectionState(RTCIceConnectionState state) = 0; + + virtual void OnIceCandidate(scoped_refptr candidate) = 0; + + virtual void OnAddStream(scoped_refptr stream) = 0; + + virtual void OnRemoveStream(scoped_refptr stream) = 0; + + virtual void OnAddTrack(scoped_refptr stream, + scoped_refptr track) = 0; + + virtual void OnRemoveTrack(scoped_refptr stream, + scoped_refptr track) = 0; + + virtual void OnDataChannel(scoped_refptr data_channel) = 0; + + virtual void OnRenegotiationNeeded() = 0; + + protected: + virtual ~RTCPeerConnectionObserver() {} +}; + +class RTCPeerConnection : public RefCountInterface { + public: + virtual int AddStream(scoped_refptr stream) = 0; + + virtual int RemoveStream(scoped_refptr stream) = 0; + + virtual scoped_refptr CreateDataChannel( + const char* label, + const RTCDataChannelInit* dataChannelDict) = 0; + + virtual void CreateOffer(OnSdpCreateSuccess success, + OnSdpCreateFailure failure, + scoped_refptr constraints) = 0; + + virtual void CreateAnswer(OnSdpCreateSuccess success, + OnSdpCreateFailure failure, + scoped_refptr constraints) = 0; + + virtual void Close() = 0; + + virtual void SetLocalDescription(const char* sdp, + const char* type, + OnSetSdpSuccess success, + OnSetSdpFailure failure) = 0; + + virtual void SetRemoteDescription(const char* sdp, + const char* type, + OnSetSdpSuccess success, + OnSetSdpFailure failure) = 0; + + virtual void AddCandidate(const char* mid, + int midx, + const char* candiate) = 0; + + virtual void RegisterRTCPeerConnectionObserver( + RTCPeerConnectionObserver* observer) = 0; + + virtual void DeRegisterRTCPeerConnectionObserver() = 0; + + virtual MediaStreamVector local_streams() = 0; + + virtual MediaStreamVector remote_streams() = 0; + + virtual bool GetStats(const RTCAudioTrack* track, + scoped_refptr observer) = 0; + + virtual bool GetStats(const RTCVideoTrack* track, + scoped_refptr observer) = 0; + + protected: + virtual ~RTCPeerConnection() {} +}; + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_PEERCONNECTION_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_peerconnection_factory.h b/windows/third_party/libwebrtc/include/rtc_peerconnection_factory.h new file mode 100644 index 0000000000..b5c01fc7d3 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_peerconnection_factory.h @@ -0,0 +1,56 @@ +#ifndef LIB_WEBRTC_RTC_PEERCONNECTION_FACTORY_HXX +#define LIB_WEBRTC_RTC_PEERCONNECTION_FACTORY_HXX + +#include "rtc_types.h" + +#include "rtc_audio_source.h" +#include "rtc_audio_track.h" +#include "rtc_media_stream.h" +#include "rtc_mediaconstraints.h" +#include "rtc_video_source.h" +#include "rtc_video_device.h" + +namespace libwebrtc { + +class RTCPeerConnection; +class RTCAudioDevice; +class RTCVideoDevice; + +class RTCPeerConnectionFactory : public RefCountInterface { + public: + virtual bool Initialize() = 0; + + virtual bool Terminate() = 0; + + virtual scoped_refptr Create( + const RTCConfiguration& configuration, + scoped_refptr constraints) = 0; + + virtual void Delete(scoped_refptr peerconnection) = 0; + + virtual scoped_refptr GetAudioDevice() = 0; + + virtual scoped_refptr GetVideoDevice() = 0; + + virtual scoped_refptr CreateAudioSource( + const char* audio_source_label) = 0; + + virtual scoped_refptr CreateVideoSource( + scoped_refptr capturer, + const char* video_source_label, + scoped_refptr constraints) = 0; + + virtual scoped_refptr CreateAudioTrack( + scoped_refptr source, + const char* track_id) = 0; + + virtual scoped_refptr CreateVideoTrack( + scoped_refptr source, + const char* track_id) = 0; + + virtual scoped_refptr CreateStream(const char* stream_id) = 0; +}; + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_PEERCONNECTION_FACTORY_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_session_description.h b/windows/third_party/libwebrtc/include/rtc_session_description.h new file mode 100644 index 0000000000..bfa1450a22 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_session_description.h @@ -0,0 +1,32 @@ +#ifndef LIB_WEBRTC_RTC_SESSION_DESCRIPTION_HXX +#define LIB_WEBRTC_RTC_SESSION_DESCRIPTION_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCSessionDescription : public RefCountInterface { + public: + enum SdpType { kOffer = 0, kPrAnswer, kAnswer }; + + public: + virtual const char* sdp() const = 0; + + virtual SdpType GetType() = 0; + + virtual const char* type() = 0; + + virtual bool ToString(char* buffer, int length) = 0; + + protected: + virtual ~RTCSessionDescription() {} +}; + +LIB_WEBRTC_API scoped_refptr CreateRTCSessionDescription( + const char* type, + const char* sdp, + SdpParseError* error); + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_SESSION_DESCRIPTION_HXX \ No newline at end of file diff --git a/windows/third_party/libwebrtc/include/rtc_types.h b/windows/third_party/libwebrtc/include/rtc_types.h new file mode 100644 index 0000000000..65739fcf52 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_types.h @@ -0,0 +1,93 @@ +#ifndef LIB_WEBRTC_RTC_TYPES_HXX +#define LIB_WEBRTC_RTC_TYPES_HXX + +#ifdef LIB_WEBRTC_API_EXPORTS +#define LIB_WEBRTC_API __declspec(dllexport) +#elif defined(LIB_WEBRTC_API_DLL) +#define LIB_WEBRTC_API __declspec(dllimport) +#elif !defined(WIN32) +#define LIB_WEBRTC_API __attribute__((visibility("default"))) +#else +#define LIB_WEBRTC_API +#endif + +#include "base/fixed_size_function.h" +#include "base/inlined_vector.h" +#include "base/refcount.h" +#include "base/scoped_ref_ptr.h" + +#ifdef WIN32 +#undef strncpy +#define strncpy strncpy_s +#endif + +namespace libwebrtc { + +enum MediaSecurityType { kSRTP_None = 0, kSDES_SRTP, kDTLS_SRTP }; + +enum { kShortStringLength = 16, kMaxStringLength = 256, kMaxIceServerSize = 8 }; + +struct IceServer { + char uri[kMaxStringLength]; + char username[kMaxStringLength]; + char password[kMaxStringLength]; +}; + +enum IceTransportsType { kNone, kRelay, kNoHost, kAll }; + +enum TcpCandidatePolicy { + kTcpCandidatePolicyEnabled, + kTcpCandidatePolicyDisabled +}; + +enum CandidateNetworkPolicy { + kCandidateNetworkPolicyAll, + kCandidateNetworkPolicyLowCost +}; + +enum RtcpMuxPolicy { + kRtcpMuxPolicyNegotiate, + kRtcpMuxPolicyRequire, +}; + +enum BundlePolicy { + kBundlePolicyBalanced, + kBundlePolicyMaxBundle, + kBundlePolicyMaxCompat +}; + +enum class SdpSemantics { kPlanB, kUnifiedPlan }; + +struct RTCConfiguration { + IceServer ice_servers[kMaxIceServerSize]; + IceTransportsType type = kAll; + BundlePolicy bundle_policy = kBundlePolicyBalanced; + RtcpMuxPolicy rtcp_mux_policy = kRtcpMuxPolicyRequire; + CandidateNetworkPolicy candidate_network_policy = kCandidateNetworkPolicyAll; + TcpCandidatePolicy tcp_candidate_policy = kTcpCandidatePolicyEnabled; + + int ice_candidate_pool_size = 0; + + MediaSecurityType srtp_type = kDTLS_SRTP; + SdpSemantics sdp_semantics = SdpSemantics::kPlanB; + bool offer_to_receive_audio = true; + bool offer_to_receive_video = true; + // private + bool use_rtp_mux = true; + uint32_t local_audio_bandwidth = 128; + uint32_t local_video_bandwidth = 512; +}; + +struct SdpParseError { + public: + // The sdp line that causes the error. + char line[kMaxStringLength]; + // Explains the error. + char description[kMaxStringLength]; +}; + +#define Vector bsp::inlined_vector + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_TYPES_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_video_device.h b/windows/third_party/libwebrtc/include/rtc_video_device.h new file mode 100644 index 0000000000..e1804517e1 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_video_device.h @@ -0,0 +1,33 @@ +#ifndef LIB_WEBRTC_RTC_VIDEO_DEVICE_HXX +#define LIB_WEBRTC_RTC_VIDEO_DEVICE_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCVideoCapturer : public RefCountInterface { + public: + virtual ~RTCVideoCapturer() {} +}; + +class RTCVideoDevice : public RefCountInterface { + public: + virtual uint32_t NumberOfDevices() = 0; + + virtual int32_t GetDeviceName(uint32_t deviceNumber, + char* deviceNameUTF8, + uint32_t deviceNameLength, + char* deviceUniqueIdUTF8, + uint32_t deviceUniqueIdUTF8Length, + char* productUniqueIdUTF8 = 0, + uint32_t productUniqueIdUTF8Length = 0) = 0; + + virtual scoped_refptr Create(const char* name, uint32_t index) = 0; + + protected: + virtual ~RTCVideoDevice() {} +}; + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_VIDEO_DEVICE_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_video_frame.h b/windows/third_party/libwebrtc/include/rtc_video_frame.h new file mode 100644 index 0000000000..de56ed71a0 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_video_frame.h @@ -0,0 +1,65 @@ +#ifndef LIB_WEBRTC_RTC_VIDEO_FRAME_HXX +#define LIB_WEBRTC_RTC_VIDEO_FRAME_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCVideoFrame : public RefCountInterface { + public: + enum class Type { kARGB, kBGRA, kABGR, kRGBA }; + + enum VideoRotation { + kVideoRotation_0 = 0, + kVideoRotation_90 = 90, + kVideoRotation_180 = 180, + kVideoRotation_270 = 270 + }; + + public: + LIB_WEBRTC_API static scoped_refptr + Create(int width, int height, const uint8_t* buffer, int length); + + LIB_WEBRTC_API static scoped_refptr Create( + int width, + int height, + const uint8_t* data_y, + int stride_y, + const uint8_t* data_u, + int stride_u, + const uint8_t* data_v, + int stride_v); + + virtual scoped_refptr Copy() = 0; + + // The resolution of the frame in pixels. For formats where some planes are + // subsampled, this is the highest-resolution plane. + virtual int width() const = 0; + virtual int height() const = 0; + + virtual VideoRotation rotation() = 0; + + // Returns pointer to the pixel data for a given plane. The memory is owned by + // the VideoFrameBuffer object and must not be freed by the caller. + virtual const uint8_t* DataY() const = 0; + virtual const uint8_t* DataU() const = 0; + virtual const uint8_t* DataV() const = 0; + + // Returns the number of bytes between successive rows for a given plane. + virtual int StrideY() const = 0; + virtual int StrideU() const = 0; + virtual int StrideV() const = 0; + + virtual int ConvertToARGB(Type type, + uint8_t* dst_argb, + int dst_stride_argb, + int dest_width, + int dest_height) = 0; + + protected: + virtual ~RTCVideoFrame() {} +}; + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_VIDEO_FRAME_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_video_renderer.h b/windows/third_party/libwebrtc/include/rtc_video_renderer.h new file mode 100644 index 0000000000..50af6821b7 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_video_renderer.h @@ -0,0 +1,18 @@ +#ifndef LIB_WEBRTC_RTC_VIDEO_RENDERER_HXX +#define LIB_WEBRTC_RTC_VIDEO_RENDERER_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +template +class RTCVideoRenderer { + public: + virtual ~RTCVideoRenderer() {} + + virtual void OnFrame(VideoFrameT frame) = 0; +}; + +}; // namespace libwebrtc + +#endif //LIB_WEBRTC_RTC_VIDEO_RENDERER_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_video_source.h b/windows/third_party/libwebrtc/include/rtc_video_source.h new file mode 100644 index 0000000000..a62be17d4b --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_video_source.h @@ -0,0 +1,14 @@ +#ifndef LIB_WEBRTC_RTC_VIDEO_SOURCE_HXX +#define LIB_WEBRTC_RTC_VIDEO_SOURCE_HXX + +#include "rtc_types.h" + +namespace libwebrtc { + +class RTCVideoSource : public RefCountInterface { + public: + ~RTCVideoSource() {} +}; +}; // namespace libwebrtc + +#endif //LIB_WEBRTC_RTC_VIDEO_SOURCE_HXX diff --git a/windows/third_party/libwebrtc/include/rtc_video_track.h b/windows/third_party/libwebrtc/include/rtc_video_track.h new file mode 100644 index 0000000000..17b60c3bb4 --- /dev/null +++ b/windows/third_party/libwebrtc/include/rtc_video_track.h @@ -0,0 +1,26 @@ +#ifndef LIB_WEBRTC_RTC_VIDEO_TRACK_HXX +#define LIB_WEBRTC_RTC_VIDEO_TRACK_HXX + +#include "rtc_types.h" + +#include "rtc_media_track.h" +#include "rtc_video_frame.h" +#include "rtc_video_renderer.h" + +namespace libwebrtc { + +class RTCVideoTrack : public RTCMediaTrack { + public: + virtual void AddRenderer( + RTCVideoRenderer>* renderer) = 0; + + virtual void RemoveRenderer( + RTCVideoRenderer>* renderer) = 0; + + protected: + ~RTCVideoTrack() {} +}; + +}; // namespace libwebrtc + +#endif // LIB_WEBRTC_RTC_VIDEO_TRACK_HXX diff --git a/windows/third_party/libwebrtc/lib/libwebrtc.dll b/windows/third_party/libwebrtc/lib/libwebrtc.dll new file mode 100644 index 0000000000..dbdedddb51 Binary files /dev/null and b/windows/third_party/libwebrtc/lib/libwebrtc.dll differ diff --git a/windows/third_party/libwebrtc/lib/libwebrtc.dll.lib b/windows/third_party/libwebrtc/lib/libwebrtc.dll.lib new file mode 100644 index 0000000000..b56651d1fb Binary files /dev/null and b/windows/third_party/libwebrtc/lib/libwebrtc.dll.lib differ diff --git a/windows/third_party/uuidxx/BUILD.gn b/windows/third_party/uuidxx/BUILD.gn new file mode 100644 index 0000000000..ad7dc082a1 --- /dev/null +++ b/windows/third_party/uuidxx/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("_uuidxx_includes") { + include_dirs = [ "." ] +} + +source_set("uuidxx") { + sources = [ + "uuidxx.cpp", + ] + public = [ + "uuidxx.h", + ] + public_configs = [ ":_uuidxx_includes" ] +} diff --git a/windows/third_party/uuidxx/LICENSE b/windows/third_party/uuidxx/LICENSE new file mode 100644 index 0000000000..6eaf314417 --- /dev/null +++ b/windows/third_party/uuidxx/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2016 by NeoSmart Technologies + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/windows/third_party/uuidxx/Makefile b/windows/third_party/uuidxx/Makefile new file mode 100644 index 0000000000..630c01664d --- /dev/null +++ b/windows/third_party/uuidxx/Makefile @@ -0,0 +1,39 @@ +prefix = /usr/local + +all: bin bin/libuuidxx.so + @echo + @echo "Build completed successfully!" + @echo "Don't forget to run \`make test\` to ensure correct functionality prior to installing with \`make install\`" + +test: bin/test + @echo + bin/test + @echo + @echo "Tests passed successfully!" + +clean: + rm -f *.o + rm -rf bin + +install: bin/libuuidxx.so bin/libuuidxx.a + cp bin/libuuidxx.so bin/libuuidxx.a $(prefix)/lib/ + +uninstall: + rm -f $(prefix)/lib/libuuidxx.so $(prefix)/lib/libuuidxx.a + +bin: + mkdir bin + +uuidxx.o: uuidxx.cpp uuidxx.h + $(CXX) $(CXXFLAGS) -std=c++11 -fPIC ./uuidxx.cpp -c -o uuidxx.o + +bin/libuuidxx.so: uuidxx.o + $(CXX) -shared uuidxx.o -o bin/libuuidxx.so + +bin/libuuidxx.a: uuidxx.o + ar rvs bin/libuuidxx.a uuidxx.o + +bin/test: bin/libuuidxx.so + $(CXX) $(CXXFLAGS) -std=c++11 bin/libuuidxx.so tests/main.cpp -o bin/test + +.PHONY: all test diff --git a/windows/third_party/uuidxx/meson.build b/windows/third_party/uuidxx/meson.build new file mode 100644 index 0000000000..c5d133ab43 --- /dev/null +++ b/windows/third_party/uuidxx/meson.build @@ -0,0 +1,33 @@ +project('uuidxx', ['cpp'], default_options: ['cpp_std=c++11']) + +safe_args = ['-Wall', '-Weffc++', '-pedantic', + '-pedantic-errors', '-Wextra', '-Wall', '-Waggregate-return', '-Wcast-align', + '-Wcast-qual', '-Wchar-subscripts', '-Wcomment', '-Wconversion', + '-Wdisabled-optimization', + '-Wfloat-equal', '-Wformat', '-Wformat=2', + '-Wformat-nonliteral', '-Wformat-security', + '-Wformat-y2k', + '-Wimport', '-Winit-self', '-Winline', + '-Winvalid-pch', + '-Wlong-long', '-Wmissing-braces', + '-Wno-missing-field-initializers', '-Wmissing-format-attribute', + '-Wmissing-include-dirs', '-Wmissing-noreturn', + '-Wpacked', '-Wparentheses', '-Wpointer-arith', + '-Wredundant-decls', '-Wreturn-type', + '-Wsequence-point', '-Wshadow', '-Wsign-compare', '-Wstack-protector', + '-Wstrict-aliasing', '-Wstrict-aliasing=2', '-Wswitch', '-Wswitch-default', + '-Wswitch-enum', '-Wtrigraphs', '-Wuninitialized', + '-Wunknown-pragmas', '-Wunreachable-code', + '-Wunused-function', '-Wunused-label', '-Wno-unused-parameter', + '-Wunused-value', '-Wunused-variable', '-Wvariadic-macros', + '-Wvolatile-register-var', '-Wwrite-strings', '-Wfatal-errors', + '-Wno-deprecated-declarations'] + +add_global_arguments(safe_args, language: ['cpp']) + +uuidxx = shared_library('uuidxx', 'uuidxx.cpp', install: true) +static_library('uuidxx', 'uuidxx.cpp', install: true) + +uudxxtest = executable('uuidxxtest', 'tests/main.cpp', link_with: uuidxx, install: false) + +test('functionality test', uudxxtest) diff --git a/windows/third_party/uuidxx/tests/main.cpp b/windows/third_party/uuidxx/tests/main.cpp new file mode 100644 index 0000000000..e62a439a16 --- /dev/null +++ b/windows/third_party/uuidxx/tests/main.cpp @@ -0,0 +1,177 @@ +#include "../uuidxx.h" +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#define strcasecmp _stricmp +#endif + +using namespace uuidxx; +using namespace std; + +bool TestEquality() +{ + bool result = true; + + uuid test1, test2; + + auto passTest = [&](bool reverse = false) { + if ((test1 != test2) ^ reverse) + { + cout << "FAIL!" << endl; + cout << "\tFailed on: " << test1.ToString() << " vs " << test2.ToString() << endl; + result = false; + } + else + { + cout << "pass" << endl; + } + }; + + cout << "Testing assignment... "; + test1 = uuid::Generate(); + test2 = test1; + passTest(); + + cout << "Testing move operator... "; + test1 = uuid::Generate(); + test2 = std::move(test1); + passTest(false); + + cout << "Testing equality of normal GUIDs... "; + test1 = uuid("2C121B80-14B1-4B5A-AD48-9043DC251FDF"); + test2 = uuid("2C121B80-14B1-4B5A-AD48-9043DC251FDF"); + passTest(); + + + cout << "Testing equality of lower- vs upper-cased GUIDs... "; + test1 = uuid("2C121B80-14B1-4B5A-AD48-9043DC251FDF"); + test2 = uuid("2c121b80-14b1-4b5a-ad48-9043dc251fdf"); + passTest(); + + cout << "Testing equality of braced vs non-braced GUIDs... "; + test1 = uuid("2C121B80-14B1-4B5A-AD48-9043DC251FDF"); + test2 = uuid("{2C121B80-14B1-4B5A-AD48-9043DC251FDF}"); + passTest(); + + cout << "Testing inequality of random GUIDs... "; + test1 = uuid::Generate(); + test2 = uuid::Generate(); + passTest(true); + + return result; +} + +bool InnerTestParsing(string test, string testCase, bool &result) +{ + cout << "Testing " << test << " parsing: " << testCase << "... "; + uuid test1(testCase); + string strValue = test1.ToString(); + if (strcasecmp(strValue.c_str(), "{A04CB1DE-25F7-4BC0-A1CE-1D0246FF362B}") != 0) + { + cout << "FAIL!" << endl; + cout << "\tFailed on: " << strValue.c_str() << " vs " << "A04CB1DE-25F7-4BC0-A1CE-1D0246FF362B" << endl; + result = false; + return false; + } + + cout << "pass" << endl; + return true; +} + +bool TestParsing() +{ + bool result = true; + + InnerTestParsing("basic", "A04CB1DE-25F7-4BC0-A1CE-1D0246FF362B", result); + InnerTestParsing("braces", "{A04CB1DE-25F7-4BC0-A1CE-1D0246FF362B}", result); + InnerTestParsing("lower-case", "a04cb1de-25f7-4bc0-a1ce-1d0246ff362b", result); + InnerTestParsing("mixed-case", "A04cb1de-25f7-4bc0-a1ce-1d0246ff362b", result); + InnerTestParsing("left-brace", "{A04CB1DE-25F7-4BC0-A1CE-1D0246FF362B", result); + InnerTestParsing("right-brace", "A04CB1DE-25F7-4BC0-A1CE-1D0246FF362B}", result); + + return result; +} + +bool TestStringGeneration() +{ + bool result = true; + + uuid test("BAA55AAB-F3FC-461C-9789-8CC6E2E2CE8C"); + + cout << "Testing generation of string without braces... "; + //don't use + //if (test.ToString(false) == "....") + //because the temporary result may be optimized away + if (strcmp(test.ToString(false).c_str(), "BAA55AAB-F3FC-461C-9789-8CC6E2E2CE8C") == 0) + { + cout << "pass" << endl; + } + else + { + cout << "FAIL!" << endl; + result = false; + } + + cout << "Testing generation of string without braces... "; + if (strcmp(test.ToString(true).c_str(), "{BAA55AAB-F3FC-461C-9789-8CC6E2E2CE8C}") == 0) + { + cout << "pass" << endl; + } + else + { + cout << "FAIL!" << endl; + result = false; + } + + return result; +} + +bool TestUniqueness() +{ + int rounds = 4096; + cout << "Generating and testing uniqueness of " << rounds << " uuids... "; + + int collisions = 0; + std::set uuidMap; + for (int i = 0; i < rounds; ++i) + { + auto test = uuid::Generate(); + if (uuidMap.insert(test).second == false) + { + ++collisions; + } + } + + if (collisions == 0) + { + cout << "pass" << endl; + return true; + } + else + { + cout << collisions << " collisions. FAIL!" << endl; + return false; + } +} + +int main (int argc, char *argv[]) +{ + auto tests = { TestStringGeneration, TestEquality, TestParsing, TestUniqueness }; + + int fails = 0; + for (auto test : tests) + { + if (!test()) + { + ++fails; + } + } + + assert(fails == 0); + return fails; +} diff --git a/windows/third_party/uuidxx/uuidxx.cc b/windows/third_party/uuidxx/uuidxx.cc new file mode 100644 index 0000000000..b8e485d965 --- /dev/null +++ b/windows/third_party/uuidxx/uuidxx.cc @@ -0,0 +1,102 @@ +#ifdef _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#endif + +#include "uuidxx.h" +#include +#include +#include +#include + +using namespace std; +using namespace uuidxx; + +bool uuid::operator == (const uuid & guid2) const +{ + return memcmp(&guid2, this, sizeof(uuid)) == 0; +} + +bool uuid::operator != (const uuid & guid2) const +{ + return !(*this == guid2); +} + +bool uuid::operator < (const uuid &guid2) const +{ + return memcmp(this, &guid2, sizeof(uuid)) < 0; +} + +bool uuid::operator > (const uuid &guid2) const +{ + return memcmp(this, &guid2, sizeof(uuid)) > 0; +} + +uuid::uuid (const std::string &uuidString) + : uuid(uuidString.c_str()) +{ +} + +uuid::uuid (const char *uuidString) +{ + if (uuidString == nullptr) + { + //special case, and prevents random bugs + memset(this, 0, sizeof(uuid)); + return; + } + + if (uuidString[0] == '{') + { + sscanf(uuidString, "{%08" SCNx32 "-%04" SCNx16 "-%04" SCNx16 "-%02" SCNx8 "%02" SCNx8 "-%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "}", &Uuid.Data1, &Uuid.Data2, &Uuid.Data3, &Uuid.Data4[0], &Uuid.Data4[1], &Uuid.Data4[2], &Uuid.Data4[3], &Uuid.Data4[4], &Uuid.Data4[5], &Uuid.Data4[6], &Uuid.Data4[7]); + } + else + { + sscanf(uuidString, "%08" SCNx32 "-%04" SCNx16 "-%04" SCNx16 "-%02" SCNx8 "%02" SCNx8 "-%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "", &Uuid.Data1, &Uuid.Data2, &Uuid.Data3, &Uuid.Data4[0], &Uuid.Data4[1], &Uuid.Data4[2], &Uuid.Data4[3], &Uuid.Data4[4], &Uuid.Data4[5], &Uuid.Data4[6], &Uuid.Data4[7]); + } +} + +string uuid::ToString(bool withBraces) const +{ + char buffer[39]; + sprintf(buffer, "%s%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X%s", withBraces ? "{" : "", Uuid.Data1, Uuid.Data2, Uuid.Data3, Uuid.Data4[0], Uuid.Data4[1], Uuid.Data4[2], Uuid.Data4[3], Uuid.Data4[4], Uuid.Data4[5], Uuid.Data4[6], Uuid.Data4[7], withBraces ? "}" : ""); + return buffer; +} + +uuid uuid::FromString(const char *uuidString) +{ + uuid temp(uuidString); + return temp; +} + +uuid uuid::FromString(const std::string &uuidString) +{ + uuid temp(uuidString.c_str()); + return temp; +} + +uuid uuid::Generatev4() +{ + //mach-o does not support TLS and clang still has issues with thread_local +#if !defined(__APPLE__) && !defined(__clang__) + thread_local std::random_device rd; + thread_local auto gen = std::mt19937_64(rd()); +#else + std::random_device rd; + std::mt19937_64 gen(rd()); +#endif + std::uniform_int_distribution dis64; + + uuid newGuid; + newGuid.WideIntegers[0] = dis64(gen); + newGuid.WideIntegers[1] = dis64(gen); + + //RFC4122 defines (psuedo)random uuids (in big-endian notation): + //MSB of DATA4[0] specifies the variant and should be 0b10 to indicate standard uuid, + //and MSB of DATA3 should be 0b0100 to indicate version 4 + newGuid.Bytes.Data4[0] = (newGuid.Bytes.Data4[0] & 0x3F) | static_cast(0x80); + newGuid.Bytes.Data3[1] = (newGuid.Bytes.Data3[1] & 0x0F) | static_cast(0x40); + + return newGuid; +} diff --git a/windows/third_party/uuidxx/uuidxx.h b/windows/third_party/uuidxx/uuidxx.h new file mode 100644 index 0000000000..a213b3af6b --- /dev/null +++ b/windows/third_party/uuidxx/uuidxx.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include + +namespace uuidxx +{ + enum class Variant + { + Nil, + Version1, + Version2, + Version3, + Version4, + Version5 + }; + + class NotImplemented : public std::logic_error + { + public: + NotImplemented() : std::logic_error("Function not yet implemented") { }; + }; + + union uuid + { + private: + static uuid Generatev4(); + + public: + uint64_t WideIntegers[2]; + struct _internalData + { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; + } Uuid; + struct _byteRepresentation + { + uint8_t Data1[4]; + uint8_t Data2[2]; + uint8_t Data3[2]; + uint8_t Data4[8]; + } Bytes; + + bool operator == (const uuid &guid2) const; + bool operator != (const uuid &guid2) const; + bool operator < (const uuid &guid2) const; + bool operator > (const uuid &guid2) const; + + uuid() = default; + + uuid(const char *uuidString); + uuid(const std::string &uuidString); + static uuid FromString(const char *uuidString); + static uuid FromString(const std::string &uuidString); + + static inline uuid Generate(Variant v = Variant::Version4) + { + switch (v) + { + case Variant::Nil: + return uuid(nullptr); //special case; + case Variant::Version1: + case Variant::Version2: + case Variant::Version3: + case Variant::Version5: + throw new NotImplemented(); + case Variant::Version4: + return Generatev4(); + } + return uuid(nullptr); + } + + std::string ToString(bool withBraces = true) const; + }; + + static_assert(sizeof(uuid) == 2 * sizeof(int64_t), "Check uuid type declaration/padding!"); +} diff --git a/windows/third_party/uuidxx/uuidxx.vcxproj b/windows/third_party/uuidxx/uuidxx.vcxproj new file mode 100644 index 0000000000..61576cf042 --- /dev/null +++ b/windows/third_party/uuidxx/uuidxx.vcxproj @@ -0,0 +1,158 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {F564A0B0-EC5D-4249-A6B9-408A2F2DDD40} + Win32Proj + uuidxx + 10.0.10586.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + \ No newline at end of file