Windows C++ でWebRTCライブラリをビルドする際の注意点

## Windowsでwebrtc(.lib/.dll)をビルドする

## 考慮する点

### ビルドにmsvc(cl.exe)がいつまで使えるのか問題

現在、Visual Studioではc++コンパイラをいくつか使用できます。
msvc(cl.exe) 
clang(clang-cl.exe)

また、WebRTCのビルド時には、"gn gen" する時に下記のオプションでコンパイラを指定できます。
is_clang=true ⇒ clangを使用する
is_clang=false ⇒ clangを使用しない

こちらにありますが、2018年3月、Google Chrome 64のビルドからは、msvcではなくclangが使用されるようになりました。当然、その中にあるWebRTCライブラリもこれに影響を受けています。
https://forest.watch.impress.co.jp/docs/serial/yajiuma/1110338.html

WebRTCライブラリをmsvcでビルドし続けることができるのかは分かりません。
https://groups.google.com/g/discuss-webrtc
で、"msvc"というキーワードを入れて検索すると、既にどんな問題が起こっているかが報告されています。「エラーが出ずにビルドできるものの、いざ使うとトラブルに見舞われる」という例もあり、無駄な時間を費やすはめになるかもしれません。

ちなみに、「Microsoftの」WinRTCプロジェクトでは、is_clang=false でビルドしています。
しかし、2021年6月の時点では、WebRTCソースコードのバージョンはm84のままになっており、さらにビルドしても、Debugビルドは使用しないでください、という状態です。（どうしてもmsvcを使用しないといけない場合、公式らしい情報としてWinRTCを参考することになるのではないでしょうか・・。）
https://github.com/microsoft/winrtc/tree/master/patches_for_WebRTC_org/m84
>gn gen --ide=vs2019 out\msvc\uwp\Release\x64 --filters=//:webrtc "--args=is_debug=false use_lld=false is_clang=false rtc_include_tests=false rtc_build_tools=false rtc_win_video_capture_winrt=true target_os=\"winuwp\" rtc_build_examples=false rtc_win_use_mf_h264=true enable_libaom=false rtc_enable_protobuf=false"

WebRTC本家サイトでは、このページに情報があるはずですが、更新されていない？
https://webrtc.github.io/webrtc-org/native-code/development/prerequisite-sw/#windows
Chroniumのビルド指示を見るようにとあるので、こちらを見てみる。
https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/windows_build_instructions.md
>The clang-cl compiler is used but Visual Studio’s header files, libraries, and some tools are required.
（「clang-clのコンパイラを使用しますが、Visual Studioのヘッダーファイル、ライブラリと各種ツールが必要になります」）

と書いてあります。つまり、Google主導のWebRTC本家サイトでは、「webrtcライブラリ本体のビルドには」clangがデフォルト指定されていると考えることができます。

参考：Clangとmsvcの比較 https://clang.llvm.org/docs/MSVCCompatibility.html

またビルドオプションに関しては、こちらの記事も必見です。
https://webrtcbydralex.com/index.php/2020/03/13/libwebrtc-compilation-flags/

#### H264関連。こんなのも。
Issue 9213: H264 support is disabled when WebRTC is built with MSVC
https://bugs.chromium.org/p/webrtc/issues/detail?id=9213#c13

```
#ifdef WEBRTC_USE_H264

#if defined(WEBRTC_WIN) && !defined(__clang__)
#error "See: bugs.webrtc.org/9213#c13."
#endif
```


### WebRTC.lib で Debugビルドが使えるのか問題

~~- 最新のWebRTCコードに追従しておられる時雨堂さんのmomoも、WindowsビルドのRelease/Debug両方で "ReleaseビルドのWebRTCライブラリ(by clang)"を使用されているようです。~~

- MicrosoftのWinRTCプロジェクト

参考１：https://github.com/microsoft/winrtc/issues/124
> I would suggest you to go with release/x64, as debug mode is not really available due to performance issues. Release/x64 mode comes with debug symbols, could be built and is perfectly debuggable. 

参考２：https://docs.microsoft.com/en-us/winrtc/getting-started
> The following instructions should work for Release builds on x64. For Debug builds and x86 builds you should harvest similar information from the webrtc.ninja file placed on its respective obj directory.
とあるので、WebRTCライブラリ(?)のDebug buildも使えるように読めるのですが・・・。

### OpenSSLとBoringSSLのどちらを使うか問題
- BoringSSLは、OpenSSLの派生版で、同じではない。
- WebRTCライブラリのソースコードもBoringSSLを多用している。
- WebRTCのビルドシステムには、  rtc_build_ssl = falseというオプションをつけてビルドし、OpenSSLを組み込むという方法も準備されていた。

https://bugs.chromium.org/p/webrtc/issues/detail?id=10160
> benwri...@webrtc.org, unfortunately, that option hasn't been working for a long time, and for example the two libraries that depends on SSL symbols (libsrtp and usrsctp) have dependencies hardcoded to boringssl in GN. 

> Comment 24 by samue...@gmail.com on Fri, Aug 7, 2020, 8:08 PM GMT+9
Hi everybody, I don't really understand where this fix is applied, because with latest WebRTC M85 when try to use it with OpenSSL I still have duplicated symbol definitions as there are still hardcoded definitions of BoringSSL dependencies in a lot of GN files... 

WebRTCネイティブライブラリをビルドする際は、"BoringSSLを使う"としてしまえればいちばん楽ですが、スタティクライブラリを作る場合には、「OpenSSLと後でバッティングしないか」を考える必要があるかもしれません。

https://github.com/google/boringssl/blob/master/INCORPORATING.md
> You cannot link multiple versions of BoringSSL or OpenSSL into a single binary without dealing with symbol conflicts. If you are statically linking multiple versions together, there's not a lot that can be done because C doesn't have a module system.

m104で下記のバグ修正が入っているらしいです。
OpenSSL build wont compile
https://bugs.chromium.org/p/webrtc/issues/detail?id=13870

### Cランタイムライブラリ(CRT)のオプションをどうするか問題
Windows用ライブラリのコードを生成する際、オプションの付け方により、ランタイムライブラリの扱いに関して対応の異なる複数のものを生成できます。

例えば、vcpkg というC++用のライブラリ管理ツールでzlibライブラリを取ってくる場合、下記の中からどれかを選択できます。

```
vcpkg install zlib:x86-windows
vcpkg install zlib:x86-windows-static
vcpkg install zlib:x86-windows-static-md
vcpkg install zlib:x64-windows
vcpkg install zlib:x64-windows-static
vcpkg install zlib:x64-windows-static-md
```

WebRTCライブラリを上記の考え方に当てはめると "x64-windows"や、"x64-windows-static" を作ることはできますが、そのままでは "x64-windows-static-md" に対応するビルドを作成することができません。

この選択に失敗すると、WebRTCライブラリを使用した自分のプログラムを作る段になって、リンカーエラー2038 に悩まされます。

Linker Tools Error LNK2038
> mismatch detected for 'name': value 'value_1' doesn't match value 'value_2' in filename.obj
https://docs.microsoft.com/ja-jp/cpp/error-messages/tool-errors/linker-tools-error-lnk2038?view=msvc-160

"x64-windows-static-md"にあたるものを作成したい場合には、**\webrtc\src\build\config\win\BUILD.gn**の下記の部分をマニュアルで調整することもできます。

```
# CRT --------------------------------------------------------------------------

# Configures how the runtime library (CRT) is going to be used.
# See https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx for a reference of
# what each value does.
config("default_crt") {
  if (is_component_build) {
    # Component mode: dynamic CRT. Since the library is shared, it requires
    # exceptions or will give errors about things not matching, so keep
    # exceptions on.
    configs = [ ":dynamic_crt" ]
  } else {
    if (current_os == "winuwp") {
      # https://blogs.msdn.microsoft.com/vcblog/2014/06/10/the-great-c-runtime-crt-refactoring/
      # contains a details explanation of what is happening with the Windows
      # CRT in Visual Studio releases related to Windows store applications.
      configs = [ ":dynamic_crt" ]
    } else {
      # Desktop Windows: static CRT.
      configs = [ ":static_crt" ]
    }
  }
}

# Use this to force use of the release CRT when building perf-critical build
# tools that need to be fully optimized even in debug builds, for those times
# when the debug CRT is part of the bottleneck. This also avoids *implicitly*
# defining _DEBUG.
config("release_crt") {
  if (is_component_build) {
    cflags = [ "/MD" ]
  } else {
    cflags = [ "/MT" ]
  }
}

config("dynamic_crt") {
  if (is_debug) {
    # This pulls in the DLL debug CRT and defines _DEBUG
    cflags = [ "/MDd" ]
  } else {
    cflags = [ "/MD" ]
  }
}

config("static_crt") {
  if (is_debug) {
    # This pulls in the static debug CRT and defines _DEBUG
    cflags = [ "/MTd" ]
  } else {
    cflags = [ "/MT" ]
  }
}
```

なお、このあたり（オプション "is_component_build"）には長年バグが存在していたようですが、下記を見ると2019年11月22日にバグ修正が終わっている？ようですので、自分の使用するコードにこの部分が含まれているかをチェックしたほうが良いと思われます。

**Issue 9419: Start supporting component builds for WebRTC**
https://bugs.chromium.org/p/webrtc/issues/detail?id=9419

### testオプションを含めないと adm2ができない問題
https://bugs.chromium.org/p/webrtc/issues/detail?id=11544

かんたんにまとめると、
- Windowsのネイティブライブラリでは、AudioDeviceModuleのバージョン2（ADM2）の使用が推奨されている。
- webrtc::CreateWindowsCoreAudioAudioDeviceModule()を使用したほうが良い
- gn gen の使用時には、「rtc_include_tests=true」というオプションがあります。
- なんと gn gen時に、rtc_include_tests=false としてテストを除外すると、このメソッドがライブラリに入らない

ということです。2021年5月14日の段階でも、"still no luck for me either"という報告が上がっています。単にビルド時に rtc_include_tests=true をつければこの問題は回避できます。

### Adm2で音声がつながらなくなる問題
webrtc::CreateWindowsCoreAudioAudioDeviceModule()を使用すると、現状では音声が出ない場合があるという報告が出ています。

[discuss-webrtc / Bug: ADM2 causes volume duck on Windows?](https://groups.google.com/g/discuss-webrtc/c/DnKMC_zl1E4/m/l_KNpnkIEAAJ)
[discuss-webrtc / changing audio device while in a call results in playout error](https://groups.google.com/g/discuss-webrtc/c/v-RsOlzblv4/m/wMlpsJhLEAAJ)

```
--- src/modules/audio_device/win/core_audio_utility_win.cc
+++ src/modules/audio_device/win/core_audio_utility_win.cc
@@ -906,7 +906,11 @@
   props.cbSize = sizeof(AudioClientProperties);
   // Real-time VoIP communication.
   // TODO(henrika): other categories?
-  props.eCategory = AudioCategory_Communications;
+
+  //https://groups.google.com/g/discuss-webrtc/c/DnKMC_zl1E4
+  props.eCategory = AudioCategory_Other;
+
   // Hardware-offloaded audio processing allows the main audio processing tasks
   // to be performed outside the computer's main CPU. Check support and log the
   // result but hard-code `bIsOffload` to FALSE for now.


```


### Windows版peerconnection_clientがきちんと動作しない問題
m98以降、Windows上でのWebRTCの動作確認アプリ peerconnection_client がきちんと動作しない、という問題があります。

下記のチケットがクローズされたら一件落着、となるはずです。
https://bugs.chromium.org/p/webrtc/issues/detail?id=13498

それまで待てない、という方は、削除されてしまった下記のファイルを復活させることを考えるのが最短だと思われます。
https://webrtc.googlesource.com/src/+/150503566c79f3cd29e90746fb16c6a9f03e47bc

そしてクライアントを下記を参考に調整します。
https://webrtc.googlesource.com/src/+/ef83d15273af1add57ee2c48e29e537c1f57f2b7%5E%21/#F0

経過としては、
1) Windowsアプリでしか使わない３つのファイルがあった
2) 全プラットフォームで共通のファイルで代用できるはず、とサンプルアプリが修正され、１）が削除された
3) その後、結果として2)がWindowsでうまく動作しなくなった
4) 現在、だれも直せていない
ということになるかと思います。

## proxy関連のファイルが /pc に移動した
2021年5月26日に下記の調整が入りました。これにより、既存アプリ/ライブラリのヘッダが急に消えて、ビルド時にあれ、どこいった？となる可能性があるので、念のため。#include のパスを /api を /pc に置き換えるだけです。勝手に消して終わりにしてはいけません。
Move proxies into pc/.
https://webrtc.googlesource.com/src//+/a1b82010094bc48d02c13cb934966296370902fa
Issue 12787: Equip WebRTC proxies with Chrome tracing entrypoints.
https://bugs.chromium.org/p/webrtc/issues/detail?id=12787
>It would be useful to be able to trace WebRTC invocations in chrome tracing. Currently this is problematic because api/proxy.h which needs some TRACE_EVENT additions is included indirectly in the Chrome build, and the TRACE_EVENT macros collide by name with the Chromium ones. This bug is filed to track evolution in this area.

## rtc::scoped_refptrへの暗黙の変換が停止する
2022年1月にrtc::scoped_refptrへの暗黙の変換をしないように修正されました。WebRTCのライブラリのコードは良いのですが、自前のコードでrtc::scoped_refptrあたりでエラーが出たら要注意です。その場合は下記で確認し、既存コードがどのように修正されているのかを確認してお手本にしましょう。

PSA: Deleting implicit conversion from raw pointer to rtc::scoped_refptr
https://groups.google.com/g/discuss-webrtc/c/jgz2st-J-_U

修正のお手本例：
Update pc/ to not use implicit T* --> scoped_refptr<T> conversion
https://webrtc.googlesource.com/src/+/e7cc8830ef53558fb8a691e5f8837ee2dedb5940



## その他
その他の問題を発見されたら教えてください。