WebRTCはウェブサイト用、ブラウザ用のAPIですが、
P2P通信による動画、音声通信APIですから、
ウェブサイト上に限らず、原理上ネイティブアプリからも使用できます。
ありがたいことに、WebRTC本家がネイティブアプリ向けのC++のライブラリを提供してくれています。
クロスプラットフォームで提供されているのですが、
iOSでの利用という意味では、若干の不便が残る状態になっています。
ほしいもの
簡単な手順でiOSアプリプロジェクトに、WebRTCライブラリを入れられるようにしたい。
現状の問題点
ビルド結果として、iOS実機用のarmv7、arm64、シミュレーター用のi386、x86_64向けのスタティックライブラリがバラバラに生成される。
Xcode開発では、複数アーキテクチャのライブラリをひとまとめにしたfatバイナリ形式のほうが取り扱いやすい。
armv7だけ出力されるライブラリや、i386だけ出力されるライブラリなどがあり、
一貫して4つアーキテクチャ入りのfatバイナリにできない。
アーキテクチャのかけたfatバイナリをXcodeに突っ込むと、ビルド時に警告が出てしまう。
ヘッダーのツリーが整理されておらず、アプリのプロジェクトに突っ込みにくい。
Bitcode Embeddingに対応していない。
AppleはBitcode対応を推奨しており、iOSアプリでも今後必須化される可能性があるので、
ライブラリもできるだけBitcode対応のものを使いたい。
やったこと
ヘッダーを含むincludeディレクトリと、
スタティックライブラリを含むlibディレクトリを生成するスクリプトをRubyで作った。
スタティックライブラリは、もしもともと特定アーキテクチャ専用であっても、
必ず4つのアーキテクチャを含むfatバイナリを生成するようにした。
Bitcode Embeddingの有効、無効どちらかを選択してビルドできるようにした。
使い方
まず、WebRTCのソースを、こちらの手順にしたがってダウンロードします。
以降では、~/webrtc-ios
にダウンロードしたという仮定で説明します。
以降では、~/webrtc-ios-build
にダウンロードしたという仮定で説明します。
スクリプトのリポジトリに移動します。
cd ~/webrtc-ios-build
スクリプトを実行します。
./webrtc-ios-build.rb --webrtc ~/webrtc-ios
~/webrtc-ios-build/include
にヘッダが出力されます。
~/webrtc-ios-build/lib
にライブラリが出力されます。
Xcodeプロジェクトに突っ込むときは、
includeはXcodeのプロジェクトに入れる必要はありません。
Build Settings > Header Search Paths
にinclude
を追加します。
Objective-Cのライブラリも使いたいときはinclude/talk/app/webrtc/objc/public
も追加します。
ライブラリは、libディレクトリごとプロジェクトに追加し、
General > Linked Frameworks And Libraries
および、
Build Phases > Link Binary With Libraries
に登録します。
加えて、Build Settings > Librari Search Paths
にlib
を追加します。
あとは普通にアプリを作ります。
Bitcode
bitcodeを無効化する場合、スクリプトに--disable-bitcode
を指定します。
サンプル
サンプルとして、GoogleのAppRTCDemoのソースと、
このツールで生成したライブラリを突っ込んで、
ビルドできるようにしたものを、
examples/AppRTCDemo
に入れてあります。
iPhoneとPC(PCはウェブ版)でビデオチャットできます。
やったこと詳細
ビルドスクリプトはRubyで実装しました。
おおまかな流れは、WebRTCのビルドを、4つのアーキテクチャで実行した後、
それを結合するというものです。
その他いくつかの手間がかかりました。
特定アーキテクチャ用のライブラリのfat化
arm専用のコードや、intel CPU専用のコードは、
そのアーキテクチャのスタティックライブラリしか生成されません。
しかし、アーキテクチャに欠けがあるfatバイナリを使うと、
Xcodeで警告が出てしまいます。
そこで、アーキテクチャに欠けがある場合は、
ダミーのスタティックライブラリを生成するようにしました。
例えば、libvpx_intrinsics_sse2.a
であれば、
下記のようなC言語のソースを生成します。
int libvpx_intrinsics_sse2_dummy_symbol() { return 0; }
Bitcodeの対応
WebRTCはchromiumプロジェクトの一部になっているのですが、
chromiumプロジェクトで、Bitcode対応が見送られているようでした。
以下のスレッドで、オープンソース版のclangがBitcodeに対応するまでは、
無効にしておこう、と言っています。
Disable ENABLE_BITCODE for iOS 9.
WebRTCのビルド設定は、src/build/common.gypi
に書かれているのですが、
ここにあるENABLE_BITCODE
をYES
にするだけでは、
残念ながら生成されるビルドスクリプトには反映されませんでした。
WebRTCは、クロスプラットフォームにするために、
ninjaスクリプトや、
Visual Studioプロジェクト、
Xcodeプロジェクトを生成するために、
gyp
というツールを使っています。(gyp公式はこちら)
gyp向けの"プロジェクトのソース"を書くと、
gypによって様々な種類のプロジェクトを生成する事ができます。
WebRTCのiOSビルドは、ninjaスクリプトを生成するのが標準とされているのですが、
gypのninjaスクリプトの生成箇所を追っかけてみると、
gyp/pylib/gyp/xcode_emulation.py
にロジックを追加すれば対応できそうでした。
xcode_emulation.py
では、GetCflags
関数で、
xcode
向けの設定を、Cコンパイラに渡すオプションに変換しています。
例えば下記のような感じです。
if 'SDKROOT' in self._Settings() and sdk_root:
cflags.append('-isysroot %s' % sdk_root)
if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'):
cflags.append('-Wconstant-conversion')
そこで、このスクリプトではこのあたりに以下のようなコードを挿入します。
if self._Test('ENABLE_BITCODE', 'YES', default='YES'):
cflags.append('-fembed-bitcode')
幸い、gypはユーザのマシンにインストールされるものではなく、
webrtcのソースと一緒に、webrtcのビルドに使う用のgypが含まれています。
なので、これを変更しても副作用はwebrtcのビルドに限られます。
このようにして、bitcode対応モードで実行された時は、
必要であればgypにパッチを当てて、
その上でcommon.gypi
の該当箇所をYES
にする、
という動作を実装することができました。
参考
How to get started with WebRTC and iOS without wasting 10 hours of your life: WebRTCをiOS向けにビルドする手順やトラブルシュートについて書かれています。
XcodeでAppRTCDemoをビルドできるようにしてみる: ほぼ同じタスクに取り組んでおられます。