├── .clang-format ├── .gitignore ├── README.md ├── cmd ├── build.go ├── root.go └── test.go ├── configs ├── linux_amd64.yml ├── linux_arm64.yml ├── linux_armhf.yml ├── linux_i386.yml └── macos_amd64.yml ├── go.mod ├── go.sum ├── main.go ├── pkg ├── build │ ├── build.go │ └── buildinfo.template └── test │ └── test.go └── test ├── Makefile └── test.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: 'Google' 3 | AccessModifierOffset: -1 4 | AlignAfterOpenBracket: 'AlwaysBreak' 5 | AlignConsecutiveAssignments: true 6 | AllowShortFunctionsOnASingleLine: 'None' 7 | AlwaysBreakAfterReturnType: 'None' 8 | AlwaysBreakTemplateDeclarations: true 9 | BreakConstructorInitializersBeforeComma: true 10 | BreakConstructorInitializers: 'AfterColon' 11 | PenaltyReturnTypeOnItsOwnLine: 120 12 | ColumnLimit: 120 13 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 14 | ConstructorInitializerIndentWidth: 4 15 | FixNamespaceComments: true 16 | IncludeBlocks: 'Regroup' 17 | IncludeCategories: 18 | - Regex: '^<.*\.h>' 19 | Priority: 1 20 | - Regex: '^<.*' 21 | Priority: 2 22 | - Regex: '.*' 23 | Priority: 3 24 | IndentPPDirectives: 'AfterHash' 25 | PointerAlignment: 'Left' 26 | SortIncludes: true 27 | SpaceAfterTemplateKeyword: false 28 | SpacesBeforeTrailingComments: 2 29 | UseTab: 'Never' 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode/ 2 | /opt/ 3 | /test/test-* 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libwebrtc for DataChannel 2 | It is a building program of WebRTC native library from Chromium. This building program configured for only enable DataChannel without multimedia features. The purpose of this repository is making easy to use WebRTC native library by sharing pre-compiled libraries. 3 | 4 | Build sequence of program is based on below documents. 5 | 6 | http://webrtc.github.io/webrtc-org/native-code/development/ 7 | 8 | This program automatically uses the latest stable version of WebRTC's source code. 9 | 10 | ## Requirements 11 | 12 | - golang 1.19 or later 13 | - Other requirement environments are depend on [`Chromium project`](https://chromium.googlesource.com/chromium/src/+/master/docs/linux/build_instructions.md) 14 | 15 | ## How to use 16 | 17 | ### Build and test for linux with amd64 18 | 19 | At amd64 linux environment. 20 | 21 | ```sh 22 | sudo dpkg --add-architecture i386 23 | go run . build 24 | go run . test 25 | ``` 26 | 27 | There is an archive file in `opt/linux_amd64`. 28 | 29 | ### Build and test for linux with i386 30 | 31 | At amd64 linux environment. 32 | 33 | ```sh 34 | sudo apt install qemu-user-static g++-i686-linux-gnu 35 | 36 | go run . build --arch=i386 37 | go run . test --arch=i386 38 | ``` 39 | 40 | There is an archive file in `opt/linux_i386`. 41 | 42 | ### Build and test for linux with armhf 43 | 44 | At amd64 linux environment. 45 | 46 | ```sh 47 | sudo apt install qemu-user-static g++-arm-linux-gnueabihf 48 | sudo ln -s /usr/arm-linux-gnueabihf/lib/ld-2.*.so /lib/ld-linux-armhf.so.3 49 | 50 | go run . build --arch=armhf 51 | LD_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib go run . test --arch=armhf 52 | ``` 53 | 54 | There is an archive file in `opt/linux_armhf`. 55 | 56 | ### Build and test for linux with arm64 57 | 58 | At amd64 linux environment. 59 | 60 | ```sh 61 | sudo apt install qemu-user-static g++-aarch64-linux-gnu 62 | sudo ln -s /usr/aarch64-linux-gnu/lib/ld-2.*.so /lib/ld-linux-aarch64.so.1 63 | 64 | go run . build --arch=arm64 65 | LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib go run . test --arch=arm64 66 | ``` 67 | 68 | There is an archive file in `opt/linux_arm64`. 69 | 70 | ### Build and test for macos 71 | 72 | At macos environment. 73 | 74 | ```sh 75 | go run . build 76 | go run . test 77 | ``` 78 | 79 | There is an archive file in `opt/macos_amd64`. 80 | 81 | ## Configuration 82 | 83 | There are configuration files in `configs/`. 84 | You can customize the build option by editing files in `configs/`. 85 | 86 | #### ChromeOsStr 87 | 88 | A string used to match the operating system of the following sites. 89 | This option is ignored without linux. 90 | 91 | https://omahaproxy.appspot.com/ 92 | 93 | #### BuildDepsOpts 94 | 95 | Options for [`install-build-deps.sh`](https://chromium.googlesource.com/chromium/src/+/master/build/install-build-deps.sh). 96 | 97 | #### GnOpts 98 | 99 | Options for GN build configuration tool. 100 | You can find help on the following pages 101 | 102 | https://www.chromium.org/developers/gn-build-configuration 103 | 104 | If you want more configuration, you can run the following command to get a list of options after executing the build once. 105 | 106 | ``` 107 | cd opt/linux_amd64/src 108 | ../../depot_tools/gn args out/Default/ --list 109 | ``` 110 | 111 | #### Headers, HeadersWithSubdir 112 | 113 | Source list of header files to be archived. 114 | The official list can be found on the following pages, but that's not enough. 115 | 116 | https://webrtc.googlesource.com/src/+/master/native-api.md 117 | 118 | ## License 119 | License follows original sources of it. See below documents. 120 | 121 | https://webrtc.org/support/license 122 | -------------------------------------------------------------------------------- /cmd/build.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path" 7 | "runtime" 8 | 9 | "github.com/llamerada-jp/libwebrtc/pkg/build" 10 | "github.com/spf13/cobra" 11 | "github.com/spf13/viper" 12 | ) 13 | 14 | var isDebug bool 15 | var targetArch string 16 | 17 | var buildCmd = &cobra.Command{ 18 | Use: "build", 19 | Short: "build libwebrtc", 20 | Long: "TBD", 21 | RunE: func(cmd *cobra.Command, args []string) error { 22 | targetOS := runtime.GOOS 23 | if targetOS == "darwin" { 24 | targetOS = "macos" 25 | } 26 | viper.SetConfigFile(path.Join("configs", fmt.Sprintf("%s_%s.yml", targetOS, targetArch))) 27 | if err := viper.ReadInConfig(); err != nil { 28 | return err 29 | } 30 | var config build.Config 31 | if err := viper.Unmarshal(&config); err != nil { 32 | return err 33 | } 34 | if err := build.Execute(&config, targetOS, targetArch, isDebug); err != nil { 35 | fmt.Fprintln(os.Stderr, err) 36 | os.Exit(1) 37 | } 38 | return nil 39 | }, 40 | } 41 | 42 | func init() { 43 | buildCmd.PersistentFlags().BoolVar(&isDebug, "is-debug", false, "enable debug flag") 44 | buildCmd.PersistentFlags().StringVar(&targetArch, "arch", "amd64", "target CPU architecture") 45 | rootCmd.AddCommand(buildCmd) 46 | } 47 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var rootCmd = &cobra.Command{ 11 | Use: "app", 12 | } 13 | 14 | func Execute() { 15 | if err := rootCmd.Execute(); err != nil { 16 | log.Println(err) 17 | os.Exit(1) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cmd/test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/llamerada-jp/libwebrtc/pkg/test" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var testArch string 12 | 13 | var testCmd = &cobra.Command{ 14 | Use: "test", 15 | Short: "test libwebrtc", 16 | Long: "TBD", 17 | RunE: func(cmd *cobra.Command, args []string) error { 18 | if err := test.Execute(testArch); err != nil { 19 | fmt.Fprintln(os.Stderr, err) 20 | os.Exit(1) 21 | } 22 | return nil 23 | }, 24 | } 25 | 26 | func init() { 27 | testCmd.PersistentFlags().StringVar(&testArch, "arch", "amd64", "target CPU architecture") 28 | rootCmd.AddCommand(testCmd) 29 | } 30 | -------------------------------------------------------------------------------- /configs/linux_amd64.yml: -------------------------------------------------------------------------------- 1 | ChromeOsStr: linux 2 | BuildDepsOpts: 3 | - '--no-arm' 4 | - '--no-chromeos-fonts' 5 | - '--no-nacl' 6 | GnOpts: 7 | - 'enable_libaom=false' 8 | - 'libyuv_disable_jpeg=true' 9 | - 'rtc_build_opus=false' 10 | - 'rtc_enable_protobuf=false' 11 | - 'rtc_include_builtin_audio_codecs=false' 12 | - 'rtc_include_builtin_video_codecs=false' 13 | - 'rtc_include_ilbc=false' 14 | - 'rtc_include_internal_audio_device=false' 15 | - 'rtc_include_opus=false' 16 | - 'rtc_include_pulse_audio=false' 17 | - 'rtc_use_dummy_audio_file_devices=true' 18 | - 'rtc_use_x11=false' 19 | - 'target_cpu="x64"' 20 | - 'target_os="linux"' 21 | - 'use_custom_libcxx=false' 22 | - 'use_libjpeg_turbo=false' 23 | - 'use_rtti=true' 24 | - 'use_system_libjpeg=true' 25 | BuildTargets: 26 | - 'peerconnection_client' 27 | NinjaFile: obj/examples/peerconnection_client.ninja 28 | NinjaTarget: 'peerconnection_client:' 29 | ExcludeFiles: 30 | - 'obj/examples' 31 | - 'obj/test' 32 | Headers: 33 | # see https://webrtc.googlesource.com/src/+/master/native-api.md for maintenance 34 | - 'common_audio/include' 35 | - 'media/base' 36 | - 'media/engine' 37 | - 'modules/audio_coding/include' 38 | - 'modules/audio_device/include' 39 | - 'modules/audio_processing/include' 40 | - 'modules/congestion_controller/include' 41 | - 'modules/include' 42 | - 'modules/rtp_rtcp/include' 43 | - 'modules/rtp_rtcp/source' 44 | - 'modules/utility/include' 45 | - 'modules/video_coding/codecs/h264/include' 46 | - 'modules/video_coding/codecs/vp8/include' 47 | - 'modules/video_coding/codecs/vp9/include' 48 | - 'modules/video_coding/include' 49 | - 'pc' 50 | - 'system_wrappers/include' 51 | # add by myself 52 | - 'call' 53 | - 'common_video' 54 | - 'common_video/include' 55 | - 'common_video/generic_frame_descriptor' 56 | - 'logging/rtc_event_log' 57 | - 'logging/rtc_event_log/events' 58 | - 'logging/rtc_event_log/encoder' 59 | - 'modules/async_audio_processing' 60 | - 'modules/rtp_rtcp/source/rtcp_packet' 61 | - 'modules/video_coding' 62 | - 'modules/video_coding/codecs/interface' 63 | - 'p2p/base' 64 | - 'video/config' 65 | HeadersWithSubdir: 66 | - 'api' 67 | # add by myself 68 | - 'rtc_base' 69 | - 'third_party/abseil-cpp/absl' 70 | -------------------------------------------------------------------------------- /configs/linux_arm64.yml: -------------------------------------------------------------------------------- 1 | ChromeOsStr: linux 2 | BuildDepsOpts: 3 | - '--arm' 4 | - '--no-chromeos-fonts' 5 | - '--no-nacl' 6 | SysrootArch: arm64 7 | GnOpts: 8 | - 'enable_libaom=false' 9 | - 'libyuv_disable_jpeg=true' 10 | - 'rtc_build_opus=false' 11 | - 'rtc_enable_protobuf=false' 12 | - 'rtc_include_builtin_audio_codecs=false' 13 | - 'rtc_include_builtin_video_codecs=false' 14 | - 'rtc_include_builtin_video_codecs=false' 15 | - 'rtc_include_ilbc=false' 16 | - 'rtc_include_internal_audio_device=false' 17 | - 'rtc_include_opus=false' 18 | - 'rtc_include_pulse_audio=false' 19 | - 'rtc_use_dummy_audio_file_devices=true' 20 | - 'rtc_use_x11=false' 21 | - 'target_cpu="arm64"' 22 | - 'target_os="linux"' 23 | # avoid build error caused by using std::is_pod 24 | - 'treat_warnings_as_errors=false' 25 | - 'use_custom_libcxx=false' 26 | - 'use_libjpeg_turbo=false' 27 | - 'use_gtk=false' 28 | - 'use_rtti=true' 29 | - 'use_system_libjpeg=true' 30 | BuildTargets: 31 | - 'peerconnection_client' 32 | NinjaFile: obj/examples/peerconnection_client.ninja 33 | NinjaTarget: 'peerconnection_client:' 34 | ExcludeFiles: 35 | - 'obj/examples' 36 | - 'obj/test' 37 | Headers: 38 | # see https://webrtc.googlesource.com/src/+/master/native-api.md for maintenance 39 | - 'common_audio/include' 40 | - 'media/base' 41 | - 'media/engine' 42 | - 'modules/audio_coding/include' 43 | - 'modules/audio_device/include' 44 | - 'modules/audio_processing/include' 45 | - 'modules/congestion_controller/include' 46 | - 'modules/include' 47 | - 'modules/rtp_rtcp/include' 48 | - 'modules/rtp_rtcp/source' 49 | - 'modules/utility/include' 50 | - 'modules/video_coding/codecs/h264/include' 51 | - 'modules/video_coding/codecs/vp8/include' 52 | - 'modules/video_coding/codecs/vp9/include' 53 | - 'modules/video_coding/include' 54 | - 'pc' 55 | - 'system_wrappers/include' 56 | - '.' 57 | - 'call' 58 | - 'common_video' 59 | - 'common_video/include' 60 | - 'common_video/generic_frame_descriptor' 61 | - 'logging/rtc_event_log' 62 | - 'logging/rtc_event_log/events' 63 | - 'logging/rtc_event_log/encoder' 64 | - 'modules/async_audio_processing' 65 | - 'modules/rtp_rtcp/source/rtcp_packet' 66 | - 'modules/video_coding' 67 | - 'modules/video_coding/codecs/interface' 68 | - 'p2p/base' 69 | - 'video/config' 70 | HeadersWithSubdir: 71 | - 'api' 72 | # add by myself 73 | - 'rtc_base' 74 | - 'third_party/abseil-cpp/absl' 75 | -------------------------------------------------------------------------------- /configs/linux_armhf.yml: -------------------------------------------------------------------------------- 1 | ChromeOsStr: linux 2 | BuildDepsOpts: 3 | - '--arm' 4 | - '--no-chromeos-fonts' 5 | - '--no-nacl' 6 | SysrootArch: arm 7 | GnOpts: 8 | - 'arm_float_abi="hard"' 9 | - 'enable_libaom=false' 10 | - 'libyuv_disable_jpeg=true' 11 | - 'rtc_build_opus=false' 12 | - 'rtc_enable_protobuf=false' 13 | - 'rtc_include_builtin_audio_codecs=false' 14 | - 'rtc_include_builtin_video_codecs=false' 15 | - 'rtc_include_builtin_video_codecs=false' 16 | - 'rtc_include_ilbc=false' 17 | - 'rtc_include_internal_audio_device=false' 18 | - 'rtc_include_opus=false' 19 | - 'rtc_include_pulse_audio=false' 20 | - 'rtc_use_dummy_audio_file_devices=true' 21 | - 'rtc_use_x11=false' 22 | - 'target_cpu="arm"' 23 | - 'target_os="linux"' 24 | # avoid build error caused by using std::is_pod 25 | - 'treat_warnings_as_errors=false' 26 | - 'use_custom_libcxx=false' 27 | - 'use_libjpeg_turbo=false' 28 | - 'use_gtk=false' 29 | - 'use_rtti=true' 30 | - 'use_system_libjpeg=true' 31 | BuildTargets: 32 | - 'peerconnection_client' 33 | NinjaFile: obj/examples/peerconnection_client.ninja 34 | NinjaTarget: 'peerconnection_client:' 35 | ExcludeFiles: 36 | - 'obj/examples' 37 | - 'obj/test' 38 | Headers: 39 | # see https://webrtc.googlesource.com/src/+/master/native-api.md for maintenance 40 | - 'common_audio/include' 41 | - 'media/base' 42 | - 'media/engine' 43 | - 'modules/audio_coding/include' 44 | - 'modules/audio_device/include' 45 | - 'modules/audio_processing/include' 46 | - 'modules/congestion_controller/include' 47 | - 'modules/include' 48 | - 'modules/rtp_rtcp/include' 49 | - 'modules/rtp_rtcp/source' 50 | - 'modules/utility/include' 51 | - 'modules/video_coding/codecs/h264/include' 52 | - 'modules/video_coding/codecs/vp8/include' 53 | - 'modules/video_coding/codecs/vp9/include' 54 | - 'modules/video_coding/include' 55 | - 'pc' 56 | - 'system_wrappers/include' 57 | # add by myself 58 | - 'call' 59 | - 'common_video' 60 | - 'common_video/include' 61 | - 'common_video/generic_frame_descriptor' 62 | - 'logging/rtc_event_log' 63 | - 'logging/rtc_event_log/events' 64 | - 'logging/rtc_event_log/encoder' 65 | - 'modules/async_audio_processing' 66 | - 'modules/rtp_rtcp/source/rtcp_packet' 67 | - 'modules/video_coding' 68 | - 'modules/video_coding/codecs/interface' 69 | - 'p2p/base' 70 | - 'video/config' 71 | HeadersWithSubdir: 72 | - 'api' 73 | # add by myself 74 | - 'rtc_base' 75 | - 'third_party/abseil-cpp/absl' 76 | -------------------------------------------------------------------------------- /configs/linux_i386.yml: -------------------------------------------------------------------------------- 1 | ChromeOsStr: linux 2 | BuildDepsOpts: 3 | - '--no-arm' 4 | - '--no-chromeos-fonts' 5 | - '--no-nacl' 6 | SysrootArch: x86 7 | GnOpts: 8 | - 'enable_libaom=false' 9 | - 'libyuv_disable_jpeg=true' 10 | - 'rtc_build_opus=false' 11 | - 'rtc_enable_protobuf=false' 12 | - 'rtc_include_builtin_audio_codecs=false' 13 | - 'rtc_include_builtin_video_codecs=false' 14 | - 'rtc_include_builtin_video_codecs=false' 15 | - 'rtc_include_ilbc=false' 16 | - 'rtc_include_internal_audio_device=false' 17 | - 'rtc_include_opus=false' 18 | - 'rtc_include_pulse_audio=false' 19 | - 'rtc_use_dummy_audio_file_devices=true' 20 | - 'rtc_use_x11=false' 21 | - 'target_cpu="x86"' 22 | - 'target_os="linux"' 23 | # avoid build error caused by using std::is_pod 24 | - 'treat_warnings_as_errors=false' 25 | - 'use_custom_libcxx=false' 26 | - 'use_libjpeg_turbo=false' 27 | - 'use_gtk=false' 28 | - 'use_rtti=true' 29 | - 'use_system_libjpeg=true' 30 | BuildTargets: 31 | - 'peerconnection_client' 32 | NinjaFile: obj/examples/peerconnection_client.ninja 33 | NinjaTarget: 'peerconnection_client:' 34 | ExcludeFiles: 35 | - 'obj/examples' 36 | - 'obj/test' 37 | Headers: 38 | # see https://webrtc.googlesource.com/src/+/master/native-api.md for maintenance 39 | - 'common_audio/include' 40 | - 'media/base' 41 | - 'media/engine' 42 | - 'modules/audio_coding/include' 43 | - 'modules/audio_device/include' 44 | - 'modules/audio_processing/include' 45 | - 'modules/congestion_controller/include' 46 | - 'modules/include' 47 | - 'modules/rtp_rtcp/include' 48 | - 'modules/rtp_rtcp/source' 49 | - 'modules/utility/include' 50 | - 'modules/video_coding/codecs/h264/include' 51 | - 'modules/video_coding/codecs/vp8/include' 52 | - 'modules/video_coding/codecs/vp9/include' 53 | - 'modules/video_coding/include' 54 | - 'pc' 55 | - 'system_wrappers/include' 56 | # add by myself 57 | - 'call' 58 | - 'common_video' 59 | - 'common_video/include' 60 | - 'common_video/generic_frame_descriptor' 61 | - 'logging/rtc_event_log' 62 | - 'logging/rtc_event_log/events' 63 | - 'logging/rtc_event_log/encoder' 64 | - 'modules/async_audio_processing' 65 | - 'modules/rtp_rtcp/source/rtcp_packet' 66 | - 'modules/video_coding' 67 | - 'modules/video_coding/codecs/interface' 68 | - 'p2p/base' 69 | - 'video/config' 70 | HeadersWithSubdir: 71 | - 'api' 72 | # add by myself 73 | - 'rtc_base' 74 | - 'third_party/abseil-cpp/absl' 75 | -------------------------------------------------------------------------------- /configs/macos_amd64.yml: -------------------------------------------------------------------------------- 1 | ChromeOsStr: mac 2 | GnOpts: 3 | - 'is_component_build=false' 4 | - 'rtc_build_opus=false' 5 | - 'rtc_enable_protobuf=false' 6 | - 'rtc_include_builtin_audio_codecs=false' 7 | - 'rtc_include_builtin_video_codecs=false' 8 | - 'rtc_include_builtin_video_codecs=false' 9 | - 'rtc_include_ilbc=false' 10 | - 'rtc_include_internal_audio_device=false' 11 | - 'rtc_include_opus=false' 12 | - 'rtc_include_pulse_audio=false' 13 | - 'rtc_use_dummy_audio_file_devices=true' 14 | - 'rtc_use_gtk=false' 15 | - 'rtc_use_x11=false' 16 | - 'target_cpu="x64"' 17 | - 'target_os="mac"' 18 | - 'use_custom_libcxx=false' 19 | - 'use_rtti=true' 20 | BuildTargets: 21 | - 'obj/sdk/mac_framework_objc_shared_library/WebRTC' 22 | NinjaFile: obj/sdk/mac_framework_objc_shared_library.ninja 23 | NinjaTarget: 'obj/sdk/mac_framework_objc_shared_library/WebRTC.TOC:' 24 | ExcludeFiles: 25 | - 'obj/examples' 26 | - 'obj/test' 27 | Headers: 28 | # see https://webrtc.googlesource.com/src/+/master/native-api.md for maintenance 29 | - 'common_audio/include' 30 | - 'media/base' 31 | - 'media/engine' 32 | - 'modules/audio_coding/include' 33 | - 'modules/audio_device/include' 34 | - 'modules/audio_processing/include' 35 | - 'modules/congestion_controller/include' 36 | - 'modules/include' 37 | - 'modules/rtp_rtcp/include' 38 | - 'modules/rtp_rtcp/source' 39 | - 'modules/utility/include' 40 | - 'modules/video_coding/codecs/h264/include' 41 | - 'modules/video_coding/codecs/vp8/include' 42 | - 'modules/video_coding/codecs/vp9/include' 43 | - 'modules/video_coding/include' 44 | - 'pc' 45 | - 'system_wrappers/include' 46 | # add by myself 47 | - 'call' 48 | - 'common_video' 49 | - 'common_video/include' 50 | - 'common_video/generic_frame_descriptor' 51 | - 'logging/rtc_event_log' 52 | - 'logging/rtc_event_log/events' 53 | - 'logging/rtc_event_log/encoder' 54 | - 'modules/async_audio_processing' 55 | - 'modules/rtp_rtcp/source/rtcp_packet' 56 | - 'modules/video_coding' 57 | - 'modules/video_coding/codecs/interface' 58 | - 'p2p/base' 59 | - 'video/config' 60 | HeadersWithSubdir: 61 | - 'api' 62 | # add by myself 63 | - 'rtc_base' 64 | - 'third_party/abseil-cpp/absl' 65 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/llamerada-jp/libwebrtc 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/spf13/cobra v1.8.0 7 | github.com/spf13/viper v1.18.2 8 | ) 9 | 10 | require ( 11 | github.com/fsnotify/fsnotify v1.7.0 // indirect 12 | github.com/hashicorp/hcl v1.0.0 // indirect 13 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 14 | github.com/magiconair/properties v1.8.7 // indirect 15 | github.com/mitchellh/mapstructure v1.5.0 // indirect 16 | github.com/pelletier/go-toml/v2 v2.1.1 // indirect 17 | github.com/sagikazarmark/locafero v0.4.0 // indirect 18 | github.com/sagikazarmark/slog-shim v0.1.0 // indirect 19 | github.com/sourcegraph/conc v0.3.0 // indirect 20 | github.com/spf13/afero v1.11.0 // indirect 21 | github.com/spf13/cast v1.6.0 // indirect 22 | github.com/spf13/pflag v1.0.5 // indirect 23 | github.com/subosito/gotenv v1.6.0 // indirect 24 | go.uber.org/atomic v1.9.0 // indirect 25 | go.uber.org/multierr v1.9.0 // indirect 26 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect 27 | golang.org/x/sys v0.16.0 // indirect 28 | golang.org/x/text v0.14.0 // indirect 29 | gopkg.in/ini.v1 v1.67.0 // indirect 30 | gopkg.in/yaml.v3 v3.0.1 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 5 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 6 | github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= 7 | github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 8 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 9 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 10 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 11 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 12 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 13 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 14 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 15 | github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= 16 | github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 17 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 18 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 19 | github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= 20 | github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= 21 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 22 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 23 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 24 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 25 | github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= 26 | github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= 27 | github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= 28 | github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= 29 | github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= 30 | github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= 31 | github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= 32 | github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= 33 | github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= 34 | github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 35 | github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= 36 | github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 37 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 38 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 39 | github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= 40 | github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= 41 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 42 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 43 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 44 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 45 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 46 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 47 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 48 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 49 | github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= 50 | github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 51 | go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= 52 | go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 53 | go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= 54 | go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= 55 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= 56 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 57 | golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= 58 | golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 59 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 60 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 61 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 62 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 63 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 64 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 65 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 66 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 67 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 68 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/llamerada-jp/libwebrtc/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /pkg/build/build.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "bufio" 5 | _ "embed" 6 | "encoding/json" 7 | "fmt" 8 | "io" 9 | "log" 10 | "net/http" 11 | "os" 12 | "os/exec" 13 | "path" 14 | "regexp" 15 | "strings" 16 | "text/template" 17 | "time" 18 | ) 19 | 20 | //go:embed buildinfo.template 21 | var BuildInfoTemplate string 22 | 23 | const ( 24 | DepotToolsURL = "https://chromium.googlesource.com/chromium/tools/depot_tools.git" 25 | ChromeInfoURL = "https://chromiumdash.appspot.com/fetch_milestones?only_branched=true" 26 | WebrtcInfoURL = "https://raw.githubusercontent.com/chromium/chromium/%s/DEPS" 27 | BuildInfoFilename = "libwebrtc_buildinfo.txt" 28 | ) 29 | 30 | type Config struct { 31 | ChromeOsStr string 32 | BuildDepsOpts []string 33 | SysrootArch *string 34 | GnOpts []string 35 | BuildTargets []string 36 | NinjaFile string 37 | NinjaTarget string 38 | ExcludeFiles []string 39 | Headers []string 40 | HeadersWithSubdir []string 41 | } 42 | 43 | type chromeInfo struct { 44 | ChromiumBranch string `json:"chromium_branch"` 45 | ChromiumMainBranchHash string `json:"chromium_main_branch_hash"` 46 | Milestone int32 `json:"milestone"` 47 | ScheduleActive bool `json:"schedule_active"` 48 | SchedulePhase string `json:"schedule_phase"` 49 | } 50 | 51 | type build struct { 52 | // directories 53 | optDir string 54 | tmpDir string 55 | workDir string 56 | 57 | TargetOS string 58 | // configurations from command line 59 | TargetArch string 60 | isDebug bool 61 | 62 | // configurations read from file 63 | config *Config 64 | 65 | // chrome infomations 66 | ChromeVersion string 67 | ChromeCommitID string 68 | WebrtcCommitID string 69 | } 70 | 71 | func command(path, name string, args ...string) { 72 | cmdStr := fmt.Sprintf("\x1b[36m%s\x1b[0m$ %s", path, name) 73 | for _, v := range args { 74 | cmdStr = cmdStr + fmt.Sprint(" ", v) 75 | } 76 | log.Println(cmdStr) 77 | 78 | cmd := exec.Command(name, args...) 79 | cmd.Dir = path 80 | cmd.Stdout = os.Stdout 81 | cmd.Stderr = os.Stderr 82 | if err := cmd.Run(); err != nil { 83 | log.Fatal(err) 84 | } 85 | } 86 | 87 | func commandStdin(path, input, name string, args ...string) { 88 | cmdStr := fmt.Sprintf("\x1b[36m%s\x1b[0m$ %s", path, name) 89 | for _, v := range args { 90 | cmdStr = cmdStr + fmt.Sprint(" ", v) 91 | } 92 | log.Println(cmdStr) 93 | 94 | cmd := exec.Command(name, args...) 95 | cmd.Dir = path 96 | cmd.Stdout = os.Stdout 97 | cmd.Stderr = os.Stderr 98 | stdin, err := cmd.StdinPipe() 99 | if err != nil { 100 | log.Fatal(err) 101 | } 102 | io.WriteString(stdin, input) 103 | stdin.Close() 104 | if err := cmd.Run(); err != nil { 105 | log.Fatal(err) 106 | } 107 | } 108 | 109 | func unlink(path string) { 110 | if _, err := os.Stat(path); !os.IsNotExist(err) { 111 | if err := os.RemoveAll(path); err != nil { 112 | log.Fatal(err) 113 | } 114 | } 115 | } 116 | 117 | func Execute(config *Config, targetOS, targetArch string, isDebug bool) error { 118 | build := &build{ 119 | config: config, 120 | TargetOS: targetOS, 121 | TargetArch: targetArch, 122 | isDebug: isDebug, 123 | } 124 | 125 | if err := build.makeDirs(); err != nil { 126 | return err 127 | } 128 | if err := build.setupDepotTools(); err != nil { 129 | return err 130 | } 131 | if err := build.getChromeInfo(); err != nil { 132 | return err 133 | } 134 | if err := build.getWebrtcInfo(); err != nil { 135 | return err 136 | } 137 | if err := build.build(); err != nil { 138 | return err 139 | } 140 | 141 | switch targetOS { 142 | case "linux": 143 | if err := build.makeLibLinux(); err != nil { 144 | return err 145 | } 146 | case "macos": 147 | if err := build.makeLibMacos(); err != nil { 148 | return err 149 | } 150 | } 151 | if err := build.collectHeaders(); err != nil { 152 | return err 153 | } 154 | if err := build.generateBuildInfo(); err != nil { 155 | return err 156 | } 157 | if err := build.makeArchive(); err != nil { 158 | return err 159 | } 160 | return nil 161 | } 162 | 163 | func (b *build) makeDirs() error { 164 | pwd, _ := os.Getwd() 165 | b.optDir = path.Join(pwd, "opt") 166 | b.workDir = path.Join(b.optDir, fmt.Sprintf("%s_%s", b.TargetOS, b.TargetArch)) 167 | b.tmpDir = path.Join(b.workDir, "tmp") 168 | 169 | unlink(path.Join(b.workDir, "include")) 170 | if err := os.MkdirAll(path.Join(b.workDir, "include"), os.ModePerm); err != nil { 171 | return err 172 | } 173 | unlink(path.Join(b.workDir, "lib")) 174 | if err := os.MkdirAll(path.Join(b.workDir, "lib"), os.ModePerm); err != nil { 175 | return err 176 | } 177 | unlink(b.tmpDir) 178 | if err := os.MkdirAll(b.tmpDir, os.ModePerm); err != nil { 179 | return err 180 | } 181 | return nil 182 | } 183 | 184 | func (b *build) setupDepotTools() error { 185 | depotToolsPath := path.Join(b.optDir, "depot_tools") 186 | 187 | if _, err := os.Stat(depotToolsPath); os.IsNotExist(err) { 188 | command("opt", "git", "clone", DepotToolsURL) 189 | 190 | } else { 191 | command(depotToolsPath, "git", "checkout", "main") 192 | command(depotToolsPath, "git", "pull") 193 | } 194 | 195 | path := os.Getenv("PATH") 196 | if err := os.Setenv("PATH", fmt.Sprintf("%s:%s", depotToolsPath, path)); err != nil { 197 | return err 198 | } 199 | 200 | return nil 201 | } 202 | 203 | func (b *build) getChromeInfo() error { 204 | httpClient := http.Client{ 205 | Timeout: 60 * time.Second, 206 | } 207 | res, err := httpClient.Get(ChromeInfoURL) 208 | if err != nil { 209 | return err 210 | } 211 | defer res.Body.Close() 212 | if res.StatusCode != http.StatusOK { 213 | return fmt.Errorf("http status code was not ok (%s) %s", res.Status, ChromeInfoURL) 214 | } 215 | var chromeInfos []chromeInfo 216 | if err := json.NewDecoder(res.Body).Decode(&chromeInfos); err != nil { 217 | return err 218 | } 219 | 220 | for _, info := range chromeInfos { 221 | if !info.ScheduleActive && info.SchedulePhase != "stable" { 222 | continue 223 | } 224 | b.ChromeCommitID = info.ChromiumMainBranchHash 225 | b.ChromeVersion = fmt.Sprintf("%d", info.Milestone) 226 | return nil 227 | } 228 | 229 | return fmt.Errorf("the infomation of chrome for specified platform was not found %v", b.config.ChromeOsStr) 230 | } 231 | 232 | func (b *build) getWebrtcInfo() error { 233 | httpClient := http.Client{ 234 | Timeout: 60 * time.Second, 235 | } 236 | res, err := httpClient.Get(fmt.Sprintf(WebrtcInfoURL, b.ChromeCommitID)) 237 | if err != nil { 238 | return err 239 | } 240 | defer res.Body.Close() 241 | 242 | scanner := bufio.NewScanner(res.Body) 243 | rep := regexp.MustCompile(`webrtc_git.*src\.git.*@.*'([a-f0-9]+)'`) 244 | for scanner.Scan() { 245 | group := rep.FindStringSubmatch(scanner.Text()) 246 | if len(group) == 2 { 247 | b.WebrtcCommitID = group[1] 248 | return nil 249 | } 250 | } 251 | 252 | return fmt.Errorf("the infomation of WebRTC was not found %v", b.ChromeCommitID) 253 | } 254 | 255 | func (b *build) build() error { 256 | if _, err := os.Stat(path.Join(b.workDir, ".gclient")); os.IsNotExist(err) { 257 | if err := os.MkdirAll(b.workDir, os.ModePerm); err != nil { 258 | return err 259 | } 260 | command(b.workDir, "fetch", "--nohooks", "webrtc") 261 | } 262 | 263 | sd := path.Join(b.workDir, "src") 264 | command(sd, "git", "fetch", "origin") 265 | // command(sd, "git", "clean", "-df") 266 | command(sd, "git", "checkout", b.WebrtcCommitID) 267 | if b.TargetOS == "linux" { 268 | depOpts := []string{"./build/install-build-deps.sh"} 269 | depOpts = append(depOpts, b.config.BuildDepsOpts...) 270 | depOpts = append(depOpts, "--no-prompt") 271 | command(sd, "sudo", depOpts...) 272 | if b.config.SysrootArch != nil { 273 | command(sd, "./build/linux/sysroot_scripts/install-sysroot.py", "--arch="+*b.config.SysrootArch) 274 | } 275 | } 276 | command(sd, "gclient", "sync", "-D") 277 | 278 | opts := b.config.GnOpts 279 | if b.isDebug { 280 | opts = append(opts, "is_debug=true") 281 | } else { 282 | opts = append(opts, "is_debug=false") 283 | } 284 | if b.config.SysrootArch != nil { 285 | opts = append(opts, "use_sysroot=true") 286 | } else { 287 | opts = append(opts, "use_sysroot=false") 288 | } 289 | command(sd, "gn", "gen", "out/Default", "--args="+strings.Join(opts, " ")) 290 | 291 | for _, buildTarget := range b.config.BuildTargets { 292 | command(sd, "ninja", "-C", path.Join("out", "Default"), buildTarget) 293 | } 294 | 295 | return nil 296 | } 297 | 298 | func (b *build) makeLibLinux() error { 299 | fp, err := os.Open(path.Join(b.workDir, "src", "out", "Default", b.config.NinjaFile)) 300 | if err != nil { 301 | return err 302 | } 303 | defer fp.Close() 304 | 305 | linkedFiles := make([]string, 0) 306 | scanner := bufio.NewScanner(fp) 307 | for scanner.Scan() { 308 | line := scanner.Text() 309 | if strings.Contains(line, b.config.NinjaTarget) { 310 | linkedFiles = append(linkedFiles, strings.Split(line, " ")...) 311 | } 312 | } 313 | oFiles := make([]string, 0) 314 | script := "create " + path.Join(b.workDir, "lib", "libwebrtc.a\n") 315 | NEXT_FILE: 316 | for _, file := range linkedFiles { 317 | for _, ex := range b.config.ExcludeFiles { 318 | if strings.Contains(file, ex) { 319 | continue NEXT_FILE 320 | } 321 | } 322 | if strings.HasSuffix(file, ".o") { 323 | oFiles = append(oFiles, path.Join("src", "out", "Default", file)) 324 | } 325 | if strings.HasSuffix(file, ".a") { 326 | script = script + "addlib " + path.Join("src", "out", "Default", file) + "\n" 327 | } 328 | } 329 | libtmp := path.Join(b.tmpDir, "libmywebrtc.a") 330 | args := append([]string{"cr", libtmp}, oFiles...) 331 | command(b.workDir, "ar", args...) 332 | script = script + "addlib " + libtmp + "\nsave\nend" 333 | unlink(path.Join(b.workDir, "libwebrtc.a")) 334 | commandStdin(b.workDir, script, "ar", "-M") 335 | return nil 336 | } 337 | 338 | func (b *build) makeLibMacos() error { 339 | fp, err := os.Open(path.Join(b.workDir, "src", "out", "Default", b.config.NinjaFile)) 340 | if err != nil { 341 | return err 342 | } 343 | defer fp.Close() 344 | 345 | linkedFiles := make([]string, 0) 346 | scanner := bufio.NewScanner(fp) 347 | for scanner.Scan() { 348 | line := scanner.Text() 349 | if strings.Contains(line, b.config.NinjaTarget) { 350 | linkedFiles = append(linkedFiles, strings.Split(line, " ")...) 351 | } 352 | } 353 | oFiles := make([]string, 0) 354 | aFiles := make([]string, 0) 355 | NEXT_FILE: 356 | for _, file := range linkedFiles { 357 | if strings.HasSuffix(file, "_objc.a") { 358 | continue 359 | } 360 | for _, ex := range b.config.ExcludeFiles { 361 | if strings.Contains(file, ex) { 362 | continue NEXT_FILE 363 | } 364 | } 365 | if strings.HasSuffix(file, ".o") { 366 | oFiles = append(oFiles, path.Join("src", "out", "Default", file)) 367 | } 368 | if strings.HasSuffix(file, ".a") { 369 | aFiles = append(aFiles, path.Join("src", "out", "Default", file)) 370 | } 371 | } 372 | libtmp := path.Join(b.tmpDir, "libmywebrtc.a") 373 | args := append([]string{"cr", libtmp}, oFiles...) 374 | command(b.workDir, "ar", args...) 375 | aFiles = append(aFiles, libtmp) 376 | args = append([]string{"-o", path.Join(b.workDir, "lib", "libwebrtc.a")}, aFiles...) 377 | command(b.workDir, "libtool", args...) 378 | return nil 379 | } 380 | 381 | func (b *build) collectHeaders() error { 382 | for _, p := range b.config.Headers { 383 | dst := path.Join(b.workDir, "include", p) 384 | src := path.Join(b.workDir, "src", p) 385 | if err := os.MkdirAll(dst, os.ModePerm); err != nil { 386 | return err 387 | } 388 | files, err := os.ReadDir(src) 389 | if err != nil { 390 | return err 391 | } 392 | for _, file := range files { 393 | if strings.HasSuffix(file.Name(), ".h") { 394 | command(b.workDir, "cp", path.Join(src, file.Name()), dst) 395 | } 396 | } 397 | } 398 | for _, p := range b.config.HeadersWithSubdir { 399 | command(path.Join(b.workDir, "src"), 400 | "find", p, "-name", "*.h", "-exec", 401 | "rsync", "-R", "{}", path.Join(b.workDir, "include"), ";") 402 | } 403 | 404 | return nil 405 | } 406 | 407 | func (b *build) generateBuildInfo() error { 408 | temp, err := template.New("buildinfo").Parse(BuildInfoTemplate) 409 | if err != nil { 410 | return err 411 | } 412 | f, err := os.Create(path.Join(b.workDir, BuildInfoFilename)) 413 | if err != nil { 414 | return err 415 | } 416 | defer f.Close() 417 | 418 | fw := bufio.NewWriter(f) 419 | err = temp.Execute(fw, *b) 420 | if err != nil { 421 | return err 422 | } 423 | return fw.Flush() 424 | } 425 | 426 | func (b *build) makeArchive() error { 427 | if b.TargetOS == "linux" { 428 | filename := fmt.Sprintf("libwebrtc-%s-linux-%s.tar.gz", b.ChromeVersion, b.TargetArch) 429 | command(b.workDir, "tar", "cvzf", filename, "include", "lib", BuildInfoFilename) 430 | } 431 | if b.TargetOS == "macos" { 432 | fname := fmt.Sprintf("libwebrtc-%s-macos-%s.zip", b.ChromeVersion, b.TargetArch) 433 | command(b.workDir, "zip", "-r", fname, "include", "lib", BuildInfoFilename) 434 | } 435 | return nil 436 | } 437 | -------------------------------------------------------------------------------- /pkg/build/buildinfo.template: -------------------------------------------------------------------------------- 1 | TARGET_OS {{.TargetOS}} 2 | TARGET_ARCH {{.TargetArch}} 3 | CHROME_VERSION {{.ChromeVersion}} 4 | CHROME_COMMIT_ID {{.ChromeCommitID}} 5 | WEBRTC_COMMIT_ID {{.WebrtcCommitID}} 6 | -------------------------------------------------------------------------------- /pkg/test/test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "os/exec" 8 | "path" 9 | ) 10 | 11 | func make(target string, args ...string) { 12 | pwd, _ := os.Getwd() 13 | testDir := path.Join(pwd, "test") 14 | cmdStr := fmt.Sprintf("\x1b[36m%s\x1b[0m$ make -C %s", pwd, testDir) 15 | for _, v := range args { 16 | cmdStr = cmdStr + fmt.Sprint(" ", v) 17 | } 18 | log.Println(cmdStr) 19 | 20 | tmpArgs := []string{ 21 | target, 22 | "-C", 23 | testDir, 24 | } 25 | 26 | tmpArgs = append(tmpArgs, args...) 27 | 28 | cmd := exec.Command("make", tmpArgs...) 29 | cmd.Dir = pwd 30 | cmd.Stdout = os.Stdout 31 | cmd.Stderr = os.Stderr 32 | if err := cmd.Run(); err != nil { 33 | log.Print(err) 34 | os.Exit(1) 35 | } 36 | } 37 | 38 | func Execute(targetArch string) error { 39 | make("run", "ARCH="+targetArch) 40 | make("clean") 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | ARCH := amd64 2 | 3 | # CPU arch 4 | ifeq ($(ARCH),amd64) 5 | QEMU := 6 | endif 7 | 8 | ifeq ($(ARCH),i386) 9 | CXX := i686-linux-gnu-g++ 10 | QEMU := qemu-i386-static 11 | endif 12 | 13 | ifeq ($(ARCH),armhf) 14 | CXX := arm-linux-gnueabihf-g++ 15 | QEMU := qemu-arm-static 16 | endif 17 | 18 | ifeq ($(ARCH),arm64) 19 | CXX := aarch64-linux-gnu-g++ 20 | QEMU := qemu-aarch64-static 21 | endif 22 | 23 | # build option 24 | CXX_FLAGS := $(CXX_FLAGS) -std=c++17 -fvisibility=hidden -fvisibility-inlines-hidden 25 | 26 | # build option by OS 27 | ifeq ($(shell uname),Linux) 28 | CXX_FLAGS := $(CXX_FLAGS) -DWEBRTC_LINUX=1 -DWEBRTC_POSIX=1 29 | LD_FLAGS := $(LD_FLAGS) -lpthread 30 | OS := linux 31 | else 32 | CXX_FLAGS := $(CXX_FLAGS) -DWEBRTC_MAC=1 -DWEBRTC_POSIX=1 33 | LD_FLAGS := $(LD_FLAGS) -framework Foundation 34 | OS := macos 35 | endif 36 | 37 | # headers 38 | LIBWEBRTC_PATH := ../opt/$(OS)_$(ARCH) 39 | CXX_FLAGS := $(CXX_FLAGS) -I $(LIBWEBRTC_PATH)/include 40 | CXX_FLAGS := $(CXX_FLAGS) -I $(LIBWEBRTC_PATH)/include/third_party/abseil-cpp 41 | 42 | # linker option 43 | LD_FLAGS := -L $(LIBWEBRTC_PATH)/lib -lwebrtc $(LD_FLAGS) 44 | 45 | default: test-$(ARCH) 46 | 47 | test-$(ARCH): test.cpp 48 | $(CXX) $(CXX_FLAGS) -o test-$(ARCH).o -c $^ -g -O0 49 | $(CXX) test-$(ARCH).o $(LD_FLAGS) -o $@ 50 | 51 | run: test-$(ARCH) 52 | $(QEMU) ./test-$(ARCH) 53 | 54 | clean: 55 | $(RM) test-* 56 | 57 | .PHONY: clean 58 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Define the macros to fit compile environment. 14 | // 環境に合わせてマクロを定義する。 15 | // #define WEBRTC_ANDROID 1 16 | // #define WEBRTC_IOS 1 17 | // #define WEBRTC_LINUX 1 18 | // #define WEBRTC_MAC 1 19 | // #define WEBRTC_POSIX 1 20 | // #define WEBRTC_WIN 1 21 | 22 | // Header files related with WebRTC. 23 | // WebRTC関連のヘッダ 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | struct Ice { 30 | std::string candidate; 31 | std::string sdp_mid; 32 | int sdp_mline_index; 33 | }; 34 | 35 | class Connection { 36 | public: 37 | const std::string name; 38 | 39 | rtc::scoped_refptr peer_connection; 40 | rtc::scoped_refptr data_channel; 41 | 42 | std::function on_sdp; 43 | std::function on_accept_ice; 44 | std::function on_ice; 45 | std::function on_success; 46 | std::function on_message; 47 | 48 | // When the status of the DataChannel changes, determine if the connection is complete. 49 | // DataChannelのstateが変化したら、接続が完了したか確かめる。 50 | void on_state_change() { 51 | std::cout << "state: " << data_channel->state() << std::endl; 52 | if (data_channel->state() == webrtc::DataChannelInterface::kOpen && on_success) { 53 | on_success(); 54 | } 55 | } 56 | 57 | // After the SDP is successfully created, it is set as a LocalDescription and displayed as a string to be passed to 58 | // the other party. 59 | // SDPの作成が成功したら、LocalDescriptionとして設定し、相手に渡す文字列として表示する。 60 | void on_success_csd(webrtc::SessionDescriptionInterface *desc) { 61 | peer_connection->SetLocalDescription(ssdo.get(), desc); 62 | 63 | std::string sdp; 64 | desc->ToString(&sdp); 65 | on_sdp(sdp); 66 | } 67 | 68 | // Convert the got ICE. 69 | // 取得したICEを変換する。 70 | void on_ice_candidate(const webrtc::IceCandidateInterface *candidate) { 71 | Ice ice; 72 | candidate->ToString(&ice.candidate); 73 | ice.sdp_mid = candidate->sdp_mid(); 74 | ice.sdp_mline_index = candidate->sdp_mline_index(); 75 | on_ice(ice); 76 | } 77 | 78 | class PCO : public webrtc::PeerConnectionObserver { 79 | private: 80 | Connection &parent; 81 | 82 | public: 83 | PCO(Connection &parent) : parent(parent) { 84 | } 85 | 86 | void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override { 87 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 88 | << "PeerConnectionObserver::SignalingChange(" << new_state << ")" << std::endl; 89 | }; 90 | 91 | void OnAddStream(rtc::scoped_refptr stream) override { 92 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 93 | << "PeerConnectionObserver::AddStream" << std::endl; 94 | }; 95 | 96 | void OnRemoveStream(rtc::scoped_refptr stream) override { 97 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 98 | << "PeerConnectionObserver::RemoveStream" << std::endl; 99 | }; 100 | 101 | void OnDataChannel(rtc::scoped_refptr data_channel) override { 102 | assert(!parent.data_channel); 103 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 104 | << "PeerConnectionObserver::DataChannel(" << data_channel->id() << ")" << std::endl; 105 | // The request recipient gets a DataChannel instance in the onDataChannel event. 106 | // リクエスト受信側は、onDataChannelイベントでDataChannelインスタンスをもらう。 107 | parent.data_channel = data_channel; 108 | parent.data_channel->RegisterObserver(&parent.dco); 109 | }; 110 | 111 | void OnRenegotiationNeeded() override { 112 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 113 | << "PeerConnectionObserver::RenegotiationNeeded" << std::endl; 114 | }; 115 | 116 | void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override { 117 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 118 | << "PeerConnectionObserver::IceConnectionChange(" << new_state << ")" << std::endl; 119 | }; 120 | 121 | void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override { 122 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 123 | << "PeerConnectionObserver::IceGatheringChange(" << new_state << ")" << std::endl; 124 | }; 125 | 126 | void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override { 127 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 128 | << "PeerConnectionObserver::IceCandidate" << std::endl; 129 | parent.on_ice_candidate(candidate); 130 | }; 131 | }; 132 | 133 | class DCO : public webrtc::DataChannelObserver { 134 | private: 135 | Connection &parent; 136 | 137 | public: 138 | DCO(Connection &parent) : parent(parent) { 139 | } 140 | 141 | void OnStateChange() override { 142 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 143 | << "DataChannelObserver::StateChange" << std::endl; 144 | parent.on_state_change(); 145 | }; 146 | 147 | // Message receipt. 148 | // メッセージ受信。 149 | void OnMessage(const webrtc::DataBuffer &buffer) override { 150 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 151 | << "DataChannelObserver::Message" << std::endl; 152 | if (parent.on_message) { 153 | parent.on_message(std::string(buffer.data.data(), buffer.data.size())); 154 | } 155 | }; 156 | 157 | void OnBufferedAmountChange(uint64_t previous_amount) override { 158 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 159 | << "DataChannelObserver::BufferedAmountChange(" << previous_amount << ")" << std::endl; 160 | }; 161 | }; 162 | 163 | class CSDO : public webrtc::CreateSessionDescriptionObserver { 164 | private: 165 | Connection &parent; 166 | 167 | public: 168 | CSDO(Connection &parent) : parent(parent) { 169 | } 170 | 171 | void OnSuccess(webrtc::SessionDescriptionInterface *desc) override { 172 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 173 | << "CreateSessionDescriptionObserver::OnSuccess" << std::endl; 174 | parent.on_success_csd(desc); 175 | }; 176 | 177 | void OnFailure(webrtc::RTCError error) override { 178 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 179 | << "CreateSessionDescriptionObserver::OnFailure" << std::endl 180 | << error.message() << std::endl; 181 | }; 182 | }; 183 | 184 | class SSDO : public webrtc::SetSessionDescriptionObserver { 185 | private: 186 | Connection &parent; 187 | 188 | public: 189 | SSDO(Connection &parent) : parent(parent) { 190 | } 191 | 192 | void OnSuccess() override { 193 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 194 | << "SetSessionDescriptionObserver::OnSuccess" << std::endl; 195 | if (parent.on_accept_ice) { 196 | parent.on_accept_ice(); 197 | } 198 | }; 199 | 200 | void OnFailure(webrtc::RTCError error) override { 201 | std::cout << parent.name << ":" << std::this_thread::get_id() << ":" 202 | << "SetSessionDescriptionObserver::OnFailure" << std::endl 203 | << error.message() << std::endl; 204 | }; 205 | }; 206 | 207 | PCO pco; 208 | DCO dco; 209 | rtc::scoped_refptr csdo; 210 | rtc::scoped_refptr ssdo; 211 | 212 | Connection(const std::string &name_) : 213 | name(name_), 214 | pco(*this), 215 | dco(*this), 216 | csdo(new rtc::RefCountedObject(*this)), 217 | ssdo(new rtc::RefCountedObject(*this)) { 218 | } 219 | }; 220 | 221 | class Wrapper { 222 | public: 223 | const std::string name; 224 | std::unique_ptr network_thread; 225 | std::unique_ptr worker_thread; 226 | std::unique_ptr signaling_thread; 227 | rtc::scoped_refptr peer_connection_factory; 228 | webrtc::PeerConnectionInterface::RTCConfiguration configuration; 229 | Connection connection; 230 | 231 | Wrapper(const std::string name_) : name(name_), connection(name_) { 232 | } 233 | 234 | void on_sdp(std::function f) { 235 | connection.on_sdp = f; 236 | } 237 | 238 | void on_accept_ice(std::function f) { 239 | connection.on_accept_ice = f; 240 | } 241 | 242 | void on_ice(std::function f) { 243 | connection.on_ice = f; 244 | } 245 | 246 | void on_success(std::function f) { 247 | connection.on_success = f; 248 | } 249 | 250 | void on_message(std::function f) { 251 | connection.on_message = f; 252 | } 253 | 254 | void init() { 255 | std::cout << name << ":" << std::this_thread::get_id() << ":" 256 | << "init Main thread" << std::endl; 257 | 258 | // Using Google's STUN server. 259 | // GoogleのSTUNサーバを利用。 260 | webrtc::PeerConnectionInterface::IceServer ice_server; 261 | ice_server.uri = "stun:stun.l.google.com:19302"; 262 | configuration.servers.push_back(ice_server); 263 | 264 | network_thread = rtc::Thread::CreateWithSocketServer(); 265 | network_thread->Start(); 266 | worker_thread = rtc::Thread::Create(); 267 | worker_thread->Start(); 268 | signaling_thread = rtc::Thread::Create(); 269 | signaling_thread->Start(); 270 | webrtc::PeerConnectionFactoryDependencies dependencies; 271 | dependencies.network_thread = network_thread.get(); 272 | dependencies.worker_thread = worker_thread.get(); 273 | dependencies.signaling_thread = signaling_thread.get(); 274 | peer_connection_factory = webrtc::CreateModularPeerConnectionFactory(std::move(dependencies)); 275 | 276 | if (peer_connection_factory.get() == nullptr) { 277 | std::cout << name << ":" << std::this_thread::get_id() << ":" 278 | << "Error on CreateModularPeerConnectionFactory." << std::endl; 279 | exit(EXIT_FAILURE); 280 | } 281 | } 282 | 283 | void create_offer_sdp() { 284 | std::cout << name << ":" << std::this_thread::get_id() << ":" 285 | << "create_offer_sdp" << std::endl; 286 | 287 | webrtc::PeerConnectionDependencies pc_dependencies(&connection.pco); 288 | auto error_or_peer_connection = 289 | peer_connection_factory->CreatePeerConnectionOrError(configuration, std::move(pc_dependencies)); 290 | if (error_or_peer_connection.ok()) { 291 | connection.peer_connection = std::move(error_or_peer_connection.value()); 292 | } else { 293 | peer_connection_factory = nullptr; 294 | std::cout << name << ":" << std::this_thread::get_id() << ":" 295 | << "Error on CreatePeerConnectionOrError." << std::endl; 296 | exit(EXIT_FAILURE); 297 | } 298 | 299 | webrtc::DataChannelInit config; 300 | // DataChannelの設定。 301 | auto error_or_data_channel = connection.peer_connection->CreateDataChannelOrError("data_channel", &config); 302 | if (error_or_data_channel.ok()) { 303 | connection.data_channel = std::move(error_or_data_channel.value()); 304 | } else { 305 | std::cout << name << ":" << std::this_thread::get_id() << ":" 306 | << "Error on CreateDataChannelOrError." << std::endl; 307 | exit(EXIT_FAILURE); 308 | } 309 | 310 | connection.data_channel->RegisterObserver(&connection.dco); 311 | connection.peer_connection->CreateOffer( 312 | connection.csdo.get(), webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); 313 | } 314 | 315 | void create_answer_sdp(const std::string ¶meter) { 316 | std::cout << name << ":" << std::this_thread::get_id() << ":" 317 | << "create_answer_sdp" << std::endl; 318 | 319 | webrtc::PeerConnectionDependencies pc_dependencies(&connection.pco); 320 | auto error_or_peer_connection = 321 | peer_connection_factory->CreatePeerConnectionOrError(configuration, std::move(pc_dependencies)); 322 | if (error_or_peer_connection.ok()) { 323 | connection.peer_connection = std::move(error_or_peer_connection.value()); 324 | } else { 325 | peer_connection_factory = nullptr; 326 | std::cout << name << ":" << std::this_thread::get_id() << ":" 327 | << "Error on CreatePeerConnectionOrError." << std::endl; 328 | exit(EXIT_FAILURE); 329 | } 330 | 331 | webrtc::SdpParseError error; 332 | std::unique_ptr session_description = 333 | webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, parameter, &error); 334 | if (!session_description) { 335 | std::cout << name << ":" << std::this_thread::get_id() << ":" 336 | << "Error on CreateSessionDescription." << std::endl 337 | << error.line << std::endl 338 | << error.description << std::endl; 339 | std::cout << name << ":" << std::this_thread::get_id() << ":" 340 | << "Offer SDP:begin" << std::endl 341 | << parameter << std::endl 342 | << "Offer SDP:end" << std::endl; 343 | exit(EXIT_FAILURE); 344 | } 345 | connection.peer_connection->SetRemoteDescription(connection.ssdo.get(), session_description.release()); 346 | connection.peer_connection->CreateAnswer( 347 | connection.csdo.get(), webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); 348 | } 349 | 350 | void push_reply_sdp(const std::string ¶meter) { 351 | std::cout << name << ":" << std::this_thread::get_id() << ":" 352 | << "push_reply_sdp" << std::endl; 353 | 354 | webrtc::SdpParseError error; 355 | std::unique_ptr session_description = 356 | webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, parameter, &error); 357 | if (!session_description) { 358 | std::cout << name << ":" << std::this_thread::get_id() << ":" 359 | << "Error on CreateSessionDescription." << std::endl 360 | << error.line << std::endl 361 | << error.description << std::endl; 362 | std::cout << name << ":" << std::this_thread::get_id() << ":" 363 | << "Answer SDP:begin" << std::endl 364 | << parameter << std::endl 365 | << "Answer SDP:end" << std::endl; 366 | exit(EXIT_FAILURE); 367 | } 368 | connection.peer_connection->SetRemoteDescription(connection.ssdo.get(), session_description.release()); 369 | } 370 | 371 | void push_ice(const Ice &ice_it) { 372 | std::cout << name << ":" << std::this_thread::get_id() << ":" 373 | << "push_ice" << std::endl; 374 | 375 | webrtc::SdpParseError err_sdp; 376 | std::unique_ptr ice( 377 | CreateIceCandidate(ice_it.sdp_mid, ice_it.sdp_mline_index, ice_it.candidate, &err_sdp)); 378 | if (!err_sdp.line.empty() && !err_sdp.description.empty()) { 379 | std::cout << name << ":" << std::this_thread::get_id() << ":" 380 | << "Error on CreateIceCandidate" << std::endl 381 | << err_sdp.line << std::endl 382 | << err_sdp.description << std::endl; 383 | exit(EXIT_FAILURE); 384 | } 385 | connection.peer_connection->AddIceCandidate(ice.get()); 386 | } 387 | 388 | void send(const std::string ¶meter) { 389 | std::cout << name << ":" << std::this_thread::get_id() << ":" 390 | << "send" << std::endl; 391 | 392 | webrtc::DataBuffer buffer(rtc::CopyOnWriteBuffer(parameter.c_str(), parameter.size()), true); 393 | std::cout << name << ":" << std::this_thread::get_id() << ":" 394 | << "Send(" << connection.data_channel->state() << ")" << std::endl; 395 | connection.data_channel->Send(buffer); 396 | } 397 | 398 | void quit() { 399 | std::cout << name << ":" << std::this_thread::get_id() << ":" 400 | << "quit" << std::endl; 401 | 402 | // Close with the thread running. 403 | // スレッドが起動した状態でCloseする。 404 | connection.peer_connection->Close(); 405 | connection.peer_connection = nullptr; 406 | connection.data_channel = nullptr; 407 | peer_connection_factory = nullptr; 408 | 409 | network_thread->Stop(); 410 | worker_thread->Stop(); 411 | signaling_thread->Stop(); 412 | } 413 | }; 414 | 415 | int main(int argc, char *argv[]) { 416 | webrtc::field_trial::InitFieldTrialsFromString(""); 417 | rtc::InitializeSSL(); 418 | 419 | std::mutex mtx; 420 | std::condition_variable cond; 421 | 422 | Wrapper webrtc1("webrtc1"); 423 | Wrapper webrtc2("webrtc2"); 424 | 425 | webrtc1.init(); 426 | webrtc2.init(); 427 | 428 | bool ice_flg1 = false; 429 | bool ice_flg2 = false; 430 | 431 | webrtc1.on_accept_ice([&]() { 432 | std::lock_guard lock(mtx); 433 | ice_flg1 = true; 434 | cond.notify_all(); 435 | }); 436 | webrtc2.on_accept_ice([&]() { 437 | std::lock_guard lock(mtx); 438 | ice_flg2 = true; 439 | cond.notify_all(); 440 | }); 441 | 442 | std::list ice_list1; 443 | std::list ice_list2; 444 | 445 | webrtc1.on_ice([&](const Ice &ice) { 446 | std::lock_guard lock(mtx); 447 | ice_list1.push_back(ice); 448 | cond.notify_all(); 449 | }); 450 | webrtc2.on_ice([&](const Ice &ice) { 451 | std::lock_guard lock(mtx); 452 | ice_list2.push_back(ice); 453 | cond.notify_all(); 454 | }); 455 | 456 | std::string message1; 457 | std::string message2; 458 | 459 | webrtc1.on_message([&](const std::string &message) { 460 | std::lock_guard lock(mtx); 461 | message1 = message; 462 | cond.notify_all(); 463 | }); 464 | webrtc2.on_message([&](const std::string &message) { 465 | std::lock_guard lock(mtx); 466 | message2 = message; 467 | cond.notify_all(); 468 | }); 469 | 470 | std::string offer_sdp; 471 | std::string answer_sdp; 472 | 473 | webrtc1.on_sdp([&](const std::string &sdp) { 474 | std::cout << "got offer sdp" << std::endl; 475 | std::lock_guard lock(mtx); 476 | offer_sdp = sdp; 477 | cond.notify_all(); 478 | }); 479 | webrtc2.on_sdp([&](const std::string &sdp) { 480 | std::cout << "got answer sdp" << std::endl; 481 | std::lock_guard lock(mtx); 482 | answer_sdp = sdp; 483 | cond.notify_all(); 484 | }); 485 | 486 | bool success_flg1 = false; 487 | bool success_flg2 = false; 488 | 489 | webrtc1.on_success([&]() { 490 | std::lock_guard lock(mtx); 491 | std::cout << "webrtc1" << std::endl; 492 | success_flg1 = true; 493 | cond.notify_all(); 494 | }); 495 | webrtc2.on_success([&]() { 496 | std::lock_guard lock(mtx); 497 | std::cout << "webrtc2" << std::endl; 498 | success_flg2 = true; 499 | cond.notify_all(); 500 | }); 501 | 502 | // start 503 | webrtc1.create_offer_sdp(); 504 | 505 | { 506 | std::cout << "waiting offer sdp" << std::endl; 507 | std::unique_lock lock(mtx); 508 | cond.wait(lock, [&]() { return !offer_sdp.empty(); }); 509 | } 510 | webrtc2.create_answer_sdp(offer_sdp); 511 | 512 | { 513 | std::cout << "waiting answer sdp" << std::endl; 514 | std::unique_lock lock(mtx); 515 | cond.wait(lock, [&]() { return !answer_sdp.empty(); }); 516 | } 517 | webrtc1.push_reply_sdp(answer_sdp); 518 | 519 | while (true) { 520 | sleep(1); 521 | std::unique_lock lock(mtx); 522 | cond.wait(lock, [&]() { return (ice_flg1 && ice_flg2); }); 523 | if (!ice_list1.empty()) { 524 | webrtc2.push_ice(ice_list1.front()); 525 | ice_list1.pop_front(); 526 | } 527 | if (!ice_list2.empty()) { 528 | webrtc1.push_ice(ice_list2.front()); 529 | ice_list2.pop_front(); 530 | } 531 | if (success_flg1 || success_flg2) { 532 | break; 533 | } 534 | } 535 | 536 | { 537 | std::cout << "waiting success" << std::endl; 538 | std::unique_lock lock(mtx); 539 | cond.wait(lock, [&]() { return (success_flg1 && success_flg2); }); 540 | } 541 | webrtc1.send("message1"); 542 | webrtc2.send("message2"); 543 | 544 | { 545 | std::cout << "waiting message" << std::endl; 546 | std::unique_lock lock(mtx); 547 | cond.wait(lock, [&]() { return (!message1.empty() && !message2.empty()); }); 548 | if (message1 == "message2" && message2 == "message1") { 549 | std::cout << "success" << std::endl; 550 | } else { 551 | std::cout << "failure" << std::endl; 552 | exit(EXIT_FAILURE); 553 | } 554 | } 555 | 556 | webrtc1.quit(); 557 | webrtc2.quit(); 558 | 559 | rtc::CleanupSSL(); 560 | return 0; 561 | } 562 | --------------------------------------------------------------------------------