diff --git a/.gitattributes b/.gitattributes index e4e478835d..e69de29bb2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +0,0 @@ -*.so filter=lfs diff=lfs merge=lfs -text -*.so.* filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/README.md b/README.md index 98aec26099..8b4e82ecee 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ Ubuntu 18.04 is the only officially supported distro at this moment. For other d ## Compilation +### Option 1: Docker (recommended) + To compile AlphaRTC, please refer to the following steps 1. Prerequisites @@ -74,6 +76,43 @@ To compile AlphaRTC, please refer to the following steps You should then be able to see two Docker images, `alphartc` and `alphartc-compile` using `sudo docker images` +### Option 2: Compile from Scratch +If you don't want to use Docker, or have other reasons to compile from scratch (e.g., you want a native Windows build), you may use this method. + +1. Grab essential tools + + You may follow the guide [here](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up) to obtain a copy of `depot_tools` + +2. Clone the repo + + ```shell + git clone https://github.com/OpenNetLab/AlphaRTC.git + ``` + +3. Sync the dependencies + ```shell + cd AlphaRTC + gclient sync + mv -fvn src/* . + ``` + +4. Generate build rules + + _Windows users_: Please use __x64 Native Tools Command Prompt for VS2017__. The clang version comes with the project is 9.0.0, hence incompatible with VS2019. + + ```shell + gn gen out/Default + ``` + +5. Comile + ```shell + ninja -C out/Default peerconnection_serverless + ``` + For Windows users, we also provide a GUI version. You may compile it via + ```shell + ninja -C out/Default peerconnection_serverless_win_gui + ``` + ## Demo AlphaRTC consists of many different components. `peerconnection_serverless` is an application for demo purposes that comes with AlphaRTC. It establishes RTC communication with another peer without the need of a server. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d232e8bedd..1352671736 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,27 +10,40 @@ trigger: exclude: - upstream/* - -pool: - vmImage: 'ubuntu-latest' - - -steps: -- checkout: self - lfs: true - -- script: make init - displayName: 'build compile environment' - -- script: make sync - displayName: 'sync dependencies' - -- script: make app - displayName: 'build application' - -- script: make release - displayName: 'build release image' - -- script: docker run -d --rm -v `pwd`/examples/peerconnection/serverless/corpus:/app -w /app --name alphartc alphartc peerconnection_serverless receiver.json - && docker exec alphartc peerconnection_serverless sender.json - displayName: 'run example' +jobs: +- job: Windows + pool: + name: AlphaRTC-build + vmImage: VS2017-Win2016 + + variables: + - name: DEPOT_TOOLS_WIN_TOOLCHAIN + value: 0 + - name: GYP_MSVS_VERSION + value: 2017 + + steps: + + - powershell: | + Invoke-WebRequest -Uri "https://storage.googleapis.com/chrome-infra/depot_tools.zip" -OutFile "depot_tools.zip" + Expand-Archive "./depot_tools.zip" + workingDirectory: $(Pipeline.Workspace) + displayName: "clone depot_tools" + + - powershell: | + Write-Host "##vso[task.prependpath]$(Pipeline.Workspace)/depot_tools" + displayName: "set path" + + - powershell: gclient sync + displayName: "sync dependencies" + + - powershell: | + Get-ChildItem -Path "src" -Recurse | Move-Item -Destination "." + Remove-Item 'src' + displayName: "move src" + + - powershell: gn gen out/Default + displayName: "generate build rules" + + - powershell: ninja -C out/Default peerconnection_serverless + displayName: "make peerconnection" diff --git a/examples/BUILD.gn b/examples/BUILD.gn index 281203cdd3..7c52355798 100644 --- a/examples/BUILD.gn +++ b/examples/BUILD.gn @@ -714,6 +714,7 @@ if (is_linux || is_win) { rtc_executable("peerconnection_serverless") { testonly = true sources = [ + "peerconnection/serverless/main.cc", "peerconnection/serverless/conductor.cc", "peerconnection/serverless/conductor.h", "peerconnection/serverless/defaults.cc", @@ -764,22 +765,67 @@ if (is_linux || is_win) { "../test:video_test_support", "//third_party/libyuv", ] + } - if (is_win) { - sources += [ - "peerconnection/serverless/main.cc", - "peerconnection/serverless/main_wnd.cc", - "peerconnection/serverless/main_wnd.h", - ] - configs += [ "//build/config/win:windowed" ] - } + if (is_win) { + rtc_executable("peerconnection_serverless_win_gui") { + testonly = true + sources = [ + "peerconnection/serverless/win/main.cc", + "peerconnection/serverless/win/main_wnd.cc", + "peerconnection/serverless/conductor.cc", + "peerconnection/serverless/conductor.h", + "peerconnection/serverless/defaults.cc", + "peerconnection/serverless/defaults.h", + "peerconnection/serverless/peer_connection_client.cc", + "peerconnection/serverless/peer_connection_client.h", + ] - if (is_linux) { - sources += [ - "peerconnection/serverless/linux/main.cc" - ] - } + deps = [ + "../api:audio_options_api", + "../api:create_peerconnection_factory", + "../api:libjingle_peerconnection_api", + "../api:scoped_refptr", + "../api/audio:audio_mixer_api", + "../api/audio_codecs:audio_codecs_api", + "../api/video:video_frame_i420", + "../api/video:video_rtp_headers", + "../api/video_codecs:video_codecs_api", + "../media:rtc_media_base", + "../p2p:rtc_p2p", + "../rtc_base:checks", + "../rtc_base/third_party/sigslot", + "../system_wrappers:field_trial", + "../test:field_trial", + "../test:platform_video_capturer", + "../test:test_support", + "//third_party/abseil-cpp/absl/memory", + "//third_party/abseil-cpp/absl/types:optional", + "../api:libjingle_peerconnection_api", + "../api/audio_codecs:builtin_audio_decoder_factory", + "../api/audio_codecs:builtin_audio_encoder_factory", + "../api/video:video_frame", + "../api/video:video_rtp_headers", + "../api/video_codecs:builtin_video_decoder_factory", + "../api/video_codecs:builtin_video_encoder_factory", + "../media:rtc_audio_video", + "../modules/audio_device", + "../modules/audio_processing", + "../modules/audio_processing:api", + "../modules/video_capture:video_capture_module", + "../pc:libjingle_peerconnection", + "../pc:peerconnection", + "../rtc_base", + "../rtc_base:rtc_base_approved", + "../rtc_base:rtc_json", + "../test:video_test_common", + "../test:test_support", + "../test:video_test_support", + "//third_party/libyuv", + ] + configs += [ "//build/config/win:windowed" ] + } } rtc_executable("peerconnection_server") { diff --git a/examples/peerconnection/serverless/linux/main.cc b/examples/peerconnection/serverless/linux/main.cc deleted file mode 100644 index 997f016eb3..0000000000 --- a/examples/peerconnection/serverless/linux/main.cc +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2012 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "examples/peerconnection/serverless/conductor.h" -#include "examples/peerconnection/serverless/peer_connection_client.h" -#include "rtc_base/ssl_adapter.h" -#include "rtc_base/string_utils.h" // For ToUtf8 -#include "system_wrappers/include/field_trial.h" - -class VideoRenderer : public rtc::VideoSinkInterface { - public: - VideoRenderer(webrtc::VideoTrackInterface* track_to_render, - MainWndCallback* callback) - : track_(track_to_render), callback_(callback) { - track_->AddOrUpdateSink(this, rtc::VideoSinkWants()); - } - ~VideoRenderer() { track_->RemoveSink(this); } - void OnFrame(const webrtc::VideoFrame& frame) { - callback_->OnFrameCallback(frame); - } - - private: - rtc::scoped_refptr track_; - MainWndCallback* callback_; -}; - -class Timer { - private: - std::vector> timers_; - - public: - template - void AddTimer(int ms, Function f) { - std::shared_ptr t = std::make_shared([=] { - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); - f(); - }); - timers_.push_back(t); - } - - ~Timer() { - for (auto thread : timers_) { - thread.get()->join(); - } - } -}; - -class MainWindowMock : public MainWindow { - private: - std::unique_ptr remote_renderer_; - MainWndCallback* callback_; - std::shared_ptr socket_thread_; - Timer t; - - public: - MainWindowMock(std::shared_ptr socket_thread) - : callback_(NULL), socket_thread_(socket_thread) {} - void RegisterObserver(MainWndCallback* callback) override { - callback_ = callback; - } - - bool IsWindow() override { return true; } - - void MessageBox(const char* caption, - const char* text, - bool is_error) override { - RTC_LOG(LS_INFO) << caption << ": " << text; - } - - UI current_ui() override { return WAIT_FOR_CONNECTION; } - - void SwitchToConnectUI() override {} - void SwitchToStreamingUI() override {} - - void StartLocalRenderer(webrtc::VideoTrackInterface* local_video) override {} - - void StopLocalRenderer() override {} - - void StartRemoteRenderer(webrtc::VideoTrackInterface* remote_video) override { - remote_renderer_.reset(new VideoRenderer(remote_video, callback_)); - } - - void StopRemoteRenderer() override { remote_renderer_.reset(); } - - void QueueUIThreadCallback(int msg_id, void* data) override { - callback_->UIThreadCallback(msg_id, data); - } - - void Close() { - RTC_LOG(INFO) << "Cleaning up"; - callback_->Close(); - socket_thread_.get()->Stop(); - } - - void StartAutoCloseTimer(int interval_ms) override { - t.AddTimer(interval_ms, std::bind(&MainWindowMock::Close, this)); - } -}; - -int main(int argc, char* argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: %s config_file\n", argv[0]); - exit(EINVAL); - } - - webrtc::field_trial::InitFieldTrialsFromString( - "WebRTC-KeepAbsSendTimeExtension/Enabled/"); // Config for - // hasAbsSendTimestamp in - // RTP Header extension - - const auto json_file_path = argv[1]; - if (!webrtc::ParseAlphaCCConfig(json_file_path)) { - perror("bad config file"); - exit(EINVAL); - } - - rtc::PhysicalSocketServer socket_server; - - std::shared_ptr thread( - new rtc::AutoSocketServerThread(&socket_server)); - - MainWindowMock wnd(thread); - - rtc::InitializeSSL(); - PeerConnectionClient client; - rtc::scoped_refptr conductor( - new rtc::RefCountedObject(&client, &wnd)); - - auto config = webrtc::GetAlphaCCConfig(); - if (config->is_receiver) { - client.StartListen(config->listening_ip, config->listening_port); - } - if (config->is_sender) { - client.StartConnect(config->dest_ip, config->dest_port); - } - - thread.get()->Run(); - - rtc::CleanupSSL(); - return 0; -} \ No newline at end of file diff --git a/examples/peerconnection/serverless/main.cc b/examples/peerconnection/serverless/main.cc index 8aee9623bf..997f016eb3 100644 --- a/examples/peerconnection/serverless/main.cc +++ b/examples/peerconnection/serverless/main.cc @@ -8,57 +8,135 @@ * be found in the AUTHORS file in the root of the source tree. */ -// clang-format off -// clang formating would change include order. -#include -#include // must come after windows.h -// clang-format on - -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "examples/peerconnection/serverless/conductor.h" -#include "examples/peerconnection/serverless/main_wnd.h" #include "examples/peerconnection/serverless/peer_connection_client.h" -#include "rtc_base/checks.h" -#include "rtc_base/constructor_magic.h" #include "rtc_base/ssl_adapter.h" #include "rtc_base/string_utils.h" // For ToUtf8 -#include "rtc_base/win32_socket_init.h" -#include "rtc_base/win32_socket_server.h" #include "system_wrappers/include/field_trial.h" -#include "test/field_trial.h" - -int PASCAL wWinMain(HINSTANCE instance, - HINSTANCE prev_instance, - wchar_t* cmd_line, - int cmd_show) { - rtc::WinsockInitializer winsock_init; - rtc::Win32SocketServer w32_ss; - rtc::Win32Thread w32_thread(&w32_ss); - rtc::ThreadManager::Instance()->SetCurrentThread(&w32_thread); - - // InitFieldTrialsFromString stores the char*, so the char array must outlive - // the application. + +class VideoRenderer : public rtc::VideoSinkInterface { + public: + VideoRenderer(webrtc::VideoTrackInterface* track_to_render, + MainWndCallback* callback) + : track_(track_to_render), callback_(callback) { + track_->AddOrUpdateSink(this, rtc::VideoSinkWants()); + } + ~VideoRenderer() { track_->RemoveSink(this); } + void OnFrame(const webrtc::VideoFrame& frame) { + callback_->OnFrameCallback(frame); + } + + private: + rtc::scoped_refptr track_; + MainWndCallback* callback_; +}; + +class Timer { + private: + std::vector> timers_; + + public: + template + void AddTimer(int ms, Function f) { + std::shared_ptr t = std::make_shared([=] { + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + f(); + }); + timers_.push_back(t); + } + + ~Timer() { + for (auto thread : timers_) { + thread.get()->join(); + } + } +}; + +class MainWindowMock : public MainWindow { + private: + std::unique_ptr remote_renderer_; + MainWndCallback* callback_; + std::shared_ptr socket_thread_; + Timer t; + + public: + MainWindowMock(std::shared_ptr socket_thread) + : callback_(NULL), socket_thread_(socket_thread) {} + void RegisterObserver(MainWndCallback* callback) override { + callback_ = callback; + } + + bool IsWindow() override { return true; } + + void MessageBox(const char* caption, + const char* text, + bool is_error) override { + RTC_LOG(LS_INFO) << caption << ": " << text; + } + + UI current_ui() override { return WAIT_FOR_CONNECTION; } + + void SwitchToConnectUI() override {} + void SwitchToStreamingUI() override {} + + void StartLocalRenderer(webrtc::VideoTrackInterface* local_video) override {} + + void StopLocalRenderer() override {} + + void StartRemoteRenderer(webrtc::VideoTrackInterface* remote_video) override { + remote_renderer_.reset(new VideoRenderer(remote_video, callback_)); + } + + void StopRemoteRenderer() override { remote_renderer_.reset(); } + + void QueueUIThreadCallback(int msg_id, void* data) override { + callback_->UIThreadCallback(msg_id, data); + } + + void Close() { + RTC_LOG(INFO) << "Cleaning up"; + callback_->Close(); + socket_thread_.get()->Stop(); + } + + void StartAutoCloseTimer(int interval_ms) override { + t.AddTimer(interval_ms, std::bind(&MainWindowMock::Close, this)); + } +}; + +int main(int argc, char* argv[]) { + if (argc != 2) { + fprintf(stderr, "Usage: %s config_file\n", argv[0]); + exit(EINVAL); + } + webrtc::field_trial::InitFieldTrialsFromString( "WebRTC-KeepAbsSendTimeExtension/Enabled/"); // Config for // hasAbsSendTimestamp in // RTP Header extension - // Read the json-format configuration file. - // File path is passed through |cmd_line| - char cmd_line_s[1024]; - wcstombs(cmd_line_s, cmd_line, 1024); - if (!webrtc::ParseAlphaCCConfig(cmd_line_s)) { - RTC_NOTREACHED(); - return -1; - }; - MainWnd wnd; - if (!wnd.Create()) { - RTC_NOTREACHED(); - return -1; + const auto json_file_path = argv[1]; + if (!webrtc::ParseAlphaCCConfig(json_file_path)) { + perror("bad config file"); + exit(EINVAL); } + + rtc::PhysicalSocketServer socket_server; + + std::shared_ptr thread( + new rtc::AutoSocketServerThread(&socket_server)); + + MainWindowMock wnd(thread); + rtc::InitializeSSL(); PeerConnectionClient client; rtc::scoped_refptr conductor( @@ -71,17 +149,9 @@ int PASCAL wWinMain(HINSTANCE instance, if (config->is_sender) { client.StartConnect(config->dest_ip, config->dest_port); } - - // Main loop. - MSG msg; - BOOL gm; - while ((gm = ::GetMessage(&msg, NULL, 0, 0)) != 0 && gm != -1) { - if (!wnd.PreTranslateMessage(&msg)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - } + + thread.get()->Run(); rtc::CleanupSSL(); return 0; -} +} \ No newline at end of file diff --git a/examples/peerconnection/serverless/win/main.cc b/examples/peerconnection/serverless/win/main.cc new file mode 100644 index 0000000000..8aee9623bf --- /dev/null +++ b/examples/peerconnection/serverless/win/main.cc @@ -0,0 +1,87 @@ +/* + * Copyright 2012 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. + */ + +// clang-format off +// clang formating would change include order. +#include +#include // must come after windows.h +// clang-format on + +#include +#include +#include + +#include "examples/peerconnection/serverless/conductor.h" +#include "examples/peerconnection/serverless/main_wnd.h" +#include "examples/peerconnection/serverless/peer_connection_client.h" +#include "rtc_base/checks.h" +#include "rtc_base/constructor_magic.h" +#include "rtc_base/ssl_adapter.h" +#include "rtc_base/string_utils.h" // For ToUtf8 +#include "rtc_base/win32_socket_init.h" +#include "rtc_base/win32_socket_server.h" +#include "system_wrappers/include/field_trial.h" +#include "test/field_trial.h" + +int PASCAL wWinMain(HINSTANCE instance, + HINSTANCE prev_instance, + wchar_t* cmd_line, + int cmd_show) { + rtc::WinsockInitializer winsock_init; + rtc::Win32SocketServer w32_ss; + rtc::Win32Thread w32_thread(&w32_ss); + rtc::ThreadManager::Instance()->SetCurrentThread(&w32_thread); + + // InitFieldTrialsFromString stores the char*, so the char array must outlive + // the application. + webrtc::field_trial::InitFieldTrialsFromString( + "WebRTC-KeepAbsSendTimeExtension/Enabled/"); // Config for + // hasAbsSendTimestamp in + // RTP Header extension + + // Read the json-format configuration file. + // File path is passed through |cmd_line| + char cmd_line_s[1024]; + wcstombs(cmd_line_s, cmd_line, 1024); + if (!webrtc::ParseAlphaCCConfig(cmd_line_s)) { + RTC_NOTREACHED(); + return -1; + }; + MainWnd wnd; + if (!wnd.Create()) { + RTC_NOTREACHED(); + return -1; + } + rtc::InitializeSSL(); + PeerConnectionClient client; + rtc::scoped_refptr conductor( + new rtc::RefCountedObject(&client, &wnd)); + + auto config = webrtc::GetAlphaCCConfig(); + if (config->is_receiver) { + client.StartListen(config->listening_ip, config->listening_port); + } + if (config->is_sender) { + client.StartConnect(config->dest_ip, config->dest_port); + } + + // Main loop. + MSG msg; + BOOL gm; + while ((gm = ::GetMessage(&msg, NULL, 0, 0)) != 0 && gm != -1) { + if (!wnd.PreTranslateMessage(&msg)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + } + + rtc::CleanupSSL(); + return 0; +} diff --git a/examples/peerconnection/serverless/main_wnd.cc b/examples/peerconnection/serverless/win/main_wnd.cc similarity index 100% rename from examples/peerconnection/serverless/main_wnd.cc rename to examples/peerconnection/serverless/win/main_wnd.cc