Compiling Google WebRTC Extensions for Android

Baruch Speiser
17 min readJul 1, 2024

--

(The Nightmare Journey You Should Avoid)

Baruch Speiser is the CTO of Cambium, where he and his team of problem-solving ninjas tackle challenges every day through delivery-oriented innovation. For more about Cambium, please visit https://www.cambium.co.il.

Introduction, Young Padawan

So I’ve been working on a streaming video software solution for a major US company based on WebRTC in Android, and we had a new requirement: make sure that the streaming video is encrypted.

Simple enough, right? Surely, this has to be available out-of-the-box, right? Everybody does streaming video over WebRTC: Google Meet, Microsoft Teams, Apple FaceTime, WhatsApp. Of course, this has to be something simple, right?

Of course! On the PeerConnection interface, there are methods for retrieving the RtpSenders and RtpReceivers. These classes have methods for setting the FrameEncryptor and setting the FrameDecryptor, and so all you have to do is use those and everything will be fine. I’ll just set them to use an AES256 FrameEncryptor/FrameDecryptor, and we’ll be good to go.

“Hmm, what’s that?”

“There’s no out-of-the-box implementation for AES256?”

“Really? Hmm. Okay, no worries, so we’ll write our own.”

I’m no stranger to JCA (Java Cryptography Architecture), I use it on lots of projects and I’m more than comfortable enough doing that on my own. I’ll just copy/paste from every other JCA implementation I’ve ever done, and voila, done in time for dinner.

And so I look at the interface — and that’s when I realize this is going to be at least one step towards the rabbit hole:

package org.webrtc;

public interface FrameEncryptor {
long getNativeFrameEncryptor();
}

public interface FrameDecryptor {
long getNativeFrameDecryptor();
}

Huh. OK. Wasn’t exactly expecting that. (Alright, to be fair, I kinda was; but give me a break, I’m trying to be cheeky here.)

Adventures in C++

Photo by Filip Mroz on Unsplash

Alright, so I guess that means I’m going to have to write my own WebRTC extension project for this, and wrap it in JNI and all that jazz. Should be easy enough. Born and raised on C++ and Java and having done lots of JNI before this, this should be old hat.

I only had to support a singular, very specific operating environment: Android 32 on an ARM64 CPU; so that should keep the C++ compilation madness to a minimum. No need to cross-compile for a mix of different target platforms; nice and simple. Simple, I told myself.

(Narrator: “It would be anything but.”)

Even though the solution wouldn’t really affect the underlying RTP protocol implementation, the company I’m working for called this enhancement “SRTP” (Secure RTP), and we set out to get started on this new feature. It’s not really SRTP, but for the lack of a better term, that’s what they were gonna call it. The name stuck.

This is where my adventure begins, and where my experience can tell you: You don’t want to do this yourself unless you are prepared for trouble. If you need this for Android, take my advice: save yourself many, many headaches and just use my prebuilt libraries.

Initial Groans: Getting the Java Dependencies.
(Minor inconveniences in comparison to the headaches to come.)

Let’s start with trivial annoyances: Getting a basic jar file dependency for the Java side of things is not as simple as adding the dependency to your POM file. Google doesn’t build it anymore, and it was never pushed to Maven’s central repository. Instead, they pushed it to JCenter, which is now defunct. Good luck with that.

Instead, you need to find a mirror build, of which there are theoretically many, and many of them were poorly documented or out-of-date. More annoyingly, most of them are packaged as an Android Archive (.aar) instead of a simple Java library (.jar), and so there wasn’t a way to conveniently drop in another Maven repository into my POM file and just run with it. I eventually just downloaded an .aar release from InfoBip, extracted the .jar file myself, and then put it in my codebase and relied on it directly as a system dependency. Elegant? No. Workable? Yes.

Now that I got that out of the way, building the Java side of things was easy enough. Here’s an abbreviated version of the Aes256FrameEncryptor:

public class Aes256FrameEncryptor implements FrameEncryptor {
private final byte[] key;
private final byte[] iv;
private long pointer;
...
public Aes256FrameEncryptor(byte[] key, byte[] iv) {
...
this.key = key;
this.iv = iv;
this.pointer = initialize();
if(this.pointer == 0) {
throw new TypeNotPresentException("Native Aes256FrameEncryptor", null);
}
}

private native long initialize();
private native void destroy(long pointer);

//These methods exist for testing the JNI and native implementation.
private native byte[] encrypt(long pointer, byte[] bytes);
public byte[] encrypt(byte[] bytes) {
return encrypt(this.pointer, bytes);
}

@Override
public long getNativeFrameEncryptor() {
return this.pointer;
}

@Override
protected void finalize() throws Throwable {
destroy(this.pointer);
super.finalize();
}

}

The Aes256FrameDecryptor is structurally identical — the Java side accepts the key and initialization vector, stores them in the class where the C++ side can fetch them through JNI, and three native methods: initialize, destroy, and either encrypt/decrypt. The C++ code will implement the native WebRTC frame encryptor/decryptor interface, return a pointer to the native instance on initialization, and then pass in that pointer for encrypting/decrypting or destruction. Easy. Add some test cases showcasing the code running in Android (we’ll need an emulator to mimic the correct CPU architecture we’re compiling for), and we can validate everything works just fine.

Time to Go Native

There was something I did know about the Google WebRTC libraries: the final build produces an shared object (for you Windows folks, that’s the Unix equivalent of a DLL) called libjingle_peer_connection_so.so — but that prebuilt .so file isn’t enough to link against because it doesn’t export all of the necessary symbols you’ll need to code against. Instead, you’ll need to use an intermediate static library, libwebrtc.a, that you can link your native code against. To get libwebrtc.a, you’ll need to build it yourself.

So here we go: at a high level, the plan was to do the following:

  1. Download the Google WebRTC source code. For those of you who aren’t familiar with C++ development, even if you already have the precompiled libraries, you’ll need some part of the source code called include files so that you know what interfaces are available.
  2. Build the Google WebRTC code. Again, an important note for those who aren’t familiar with C++ development: you need to make sure you compile your code with a compatible toolchain and compiler targets. Because C++ compiles to code that runs directly against the CPU, without an interpreter or virtual machine in between, you need to make sure you are compiling your code using the precise settings that your execution environment needs, or otherwise everything explodes.
  3. Write and compile my own C++ project that implements the necessary interfaces. This means writing code both to satisfy the C++ FrameEncryptorInterface and FrameDecryptorInterface, but also the necessary JNI headers and bridge code to align with the Java side.

This is the part where I tell you everything went sideways. Multiple times.

Step 1: Getting the Code.
(About as straightforward as getting gold from leprechauns.)

Photo by Harry Quan on Unsplash

First, I attempted to download the Google WebRTC code to my local Ubuntu machine. The problem is that you can’t do this like you do for most projects: it’s a multistep process involving custom Google tools for downloading the codebase and its dependencies. (Trying to do this in Windows seemed like folly.) Trying to install them actually crashed my Ubuntu laptop. When it happened the first time, I thought it was a fluke. After the second crash… yikes.

Alright, time to sandbox it. So I broke out the Docker toolkit and prepared myself an image that would fetch the code instead. I figured this would also help me in Windows, because I could just run the container there and have an Ubuntu sandbox to fetch and build the code and even Windows would be workable.

The next problem is the seemingly innocuous “gclient sync” command that you need to run as part of getting all of the code. Remember how I recommended that you not do this yourself? Well, little did I know that it would take about THREE WHOLE GODFORSAKEN DAYS for that sucker to finish. I have no idea why it took so ridiculously long, but I had to leave it running for more than a weekend for it to finish downloading everything.

(Can you imagine reporting this to your project manager? “Hey, I would love to start coding this, but I’m still waiting for it to download…” Most project managers would question if I had suffered an appoplexy.)

In any case, after finally downloading the codebase through my specialized container, I was ready to build. Right?

Step 2: Building the Code.
(AKA, making a nefarious pact with a diabolical compiler demon.)

Photo by Dalton Smith on Unsplash

The documentation indicates that you should run the following command:

gn gen out/Debug --args='target_os="android" target_cpu="arm"'

Starting with that, and after some tweaks and my CPU churns for a while, the build breaks:

[6619/6668] ACTION //tools_webrtc:binary_version_check(//build/toolchain/android:android_clang_arm)
FAILED: webrtc_binary_version_check
vpython3 ../../tools_webrtc/binary_version_check.py libjingle_peerconnection_so.so
Traceback (most recent call last):
File "/build_android_webrtc/src/out/Release/../../tools_webrtc/binary_version_check.py", line 26, in <module>
output = subprocess.check_output(['strings', filename])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/.cache/.vpython-root/store/cpython+qocd3gso2qlupcvi74a8cf00v0/contents/lib/python3.11/subprocess.py", line 466, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/.cache/.vpython-root/store/cpython+qocd3gso2qlupcvi74a8cf00v0/contents/lib/python3.11/subprocess.py", line 548, in run
with Popen(*popenargs, **kwargs) as process:
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/.cache/.vpython-root/store/cpython+qocd3gso2qlupcvi74a8cf00v0/contents/lib/python3.11/subprocess.py", line 1026, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/root/.cache/.vpython-root/store/cpython+qocd3gso2qlupcvi74a8cf00v0/contents/lib/python3.11/subprocess.py", line 1953, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'strings'

It would have been nice if Google had documented that you need an updated binutils, but I guess we can’t have everything. It took several iterations of builds before I had added all of the undocumented prerequisite software necessary. Eventually, though, the build completes; and my laptop is practically melting from the CPU heat.

For those of you attempting this on your own (again, ill-advised), the next problem you’ll encounter when following the limited Google documentation for building WebRTC is that you will likely discover you are building for the wrong CPU architecture.

The problem is that the barebones documentation doesn’t make it clear that the ‘arm’ option is for older 32-bit ARM v7 architectures. This will build fine, but then you’ll start building your C++ extensions that rely on it and you’ll get the worst kind of obscure linking errors, like misaligned frame tables:

unknown relocation (315) against symbol typeinfo

Which, by the way, is a total red herring. You would think that would imply a problem with position independent code setting in the compiler, and you need to figure out how to add the -fPIC parameter. But nope. Truth is, libwebrtc is already compiled with the -fPIC setting and the linking errors have to do with a CPU mismatch.

Here’s the thing that makes this an even worse trip down the rabbit hole: The libwebrtc code isn’t organized to build under conventional, standard, normal, everyday CMake. Nope. That would be too easy, of course. No, instead, Google uses their own custom toolkit called GN, which directly generates Ninja build files. So if you’re trying to figure out where the heck is the CMAKE_POSITION_INDEPENDENT_CODE flag set in CMake for libwebrtc, you’re not going to find it.

After fruitlessly trying to figure out why the fPIC flag wasn’t working, I went back to basics and went full-on diagnostics mode. I was gonna Sherlock Holmes that sucker, and so I started readelf-ing everything. Sure enough:

readelf -h libwebrtc/src/out/Release/obj/libwebrtc.a | grep 'Class\|File\|Machine'

…and the damn thing tells me it’s ELF32 ARM. I was looking for ELF64 AARCH. Blargh.

So now I started looking through Google’s GN code, eventually navigating my way into the correct parameter options. After spelunking for a lot longer than I would have liked, I finally figure out that the correct parameter value for target_cpu is “arm64” and not just “arm”.

Fine. Some might argue that’s a reasonable documentation ambiguity, or if you want to blame me, maybe that should have been obvious. Whatever, fair enough; solved now. Small victories. Proceed. Forward march.

Step 3: Write & Build my Extension Code.
(Don’t worry, we’ll circle back to the compiler demons; patience.)

Now all I needed was to reference all of the necessary headers. I only need to reference two interfaces in the libwebrtc code, so it should be relatively straightforward. Similarly, I had the libwebrtc.a static library; should be easy enough.

Nightmare 1: Mismatched Toolchains

Apparently, by default, Google builds libwebrtc with a custom toolchain. The libwebrtc dependencies actually include a custom version of the LLVM compiler toolchain. When you build the code with it, it generates everything in a specialized Chromium-based “CR_” namespace, and so none of your STL objects match. Your code’s STL relies on standard, conventional namespace symbols from the Android NDK; but your libwebrtc.a expects a whole different namespace.

(For all of you non-C++ people reading this, STL contains really important foundational classes essential for basic development, like std::string. If your STL libraries don’t match, you’re totally and utterly screwed.)

So you have two paths forward:

  1. Build your code using the custom libwebrtc toolchain.
  2. Build their code using a standard Android NDK toolchain.

Back to Step 2: Rebuilding libwebrtc with the NDK.
(Diabolical compiler demons be damned.)

Option 1 is clearly a recipe for trouble with a side of chaos, and so pursuing option 2 was my immediate direction. Thankfully, there is a solution: with some research, I discovered you can pass a GN flag to avoid using a custom toolchain:

use_custom_libcxx=false

Elegant? Yes. Workable? No.

Sadly, this option is broken. If you use this flag, the libwebrtc build fails:

[6143/6511] LINK ./stun_prober
FAILED: stun_prober exe.unstripped/stun_prober
"vpython3" "../../build/toolchain/gcc_link_wrapper.py" --output="./stun_prober" --strip="../../third_party/llvm-build/Release+Asserts/bin/llvm-strip" --unstripped-file="./exe.unstripped/stun_prober" -- ../../third_party/llvm-build/Release+Asserts/bin/clang++ -Werror -fuse-ld=lld -Wl,--fatal-warnings -Wl,--build-id -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--icf=all -Wl,--color-diagnostics -Wl,--no-rosegment -Wl,--undefined-version -Wl,--no-call-graph-profile-sort -Wl,--exclude-libs=libvpx_assembly_arm.a -Wl,-z,max-page-size=4096 --target=arm-linux-androideabi21 -no-canonical-prefixes -Wl,--warn-shared-textrel -Wl,--gc-sections -Wl,-z,defs -Wl,--as-needed --unwindlib=none --sysroot=../../third_party/android_toolchain/ndk/toolchains/llvm/prebuilt/linux-x86_64/sysroot -pie -Bdynamic -Wl,-z,nocopyreloc -o "./exe.unstripped/stun_prober" -Wl,--start-group @"./stun_prober.rsp" -Wl,--end-group -ldl -lm -llog -lGLESv2
ld.lld: error: undefined symbol: _Unwind_Backtrace
>>> referenced by stacktrace.cc:260 (../../sdk/android/native_api/stacktrace/stacktrace.cc:260)
>>> native_api_stacktrace/stacktrace.o:(webrtc::GetStackTrace()) in archive obj/sdk/android/libnative_api_stacktrace.a
ld.lld: error: undefined symbol: _Unwind_VRS_Get
>>> referenced by unwind.h:219 (../../third_party/llvm-build/Release+Asserts/lib/clang/19/include/unwind.h:219)
>>> native_api_stacktrace/stacktrace.o:(webrtc::(anonymous namespace)::SignalHandlerOutputState::UnwindBacktrace(_Unwind_Context*, void*)) in archive obj/sdk/android/libnative_api_stacktrace.a
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
...
ninja: build stopped: subcommand failed.

Yuck. Sigh, nightmare chaos option #1 it is, then. Rebuild libwebrtc again (this time, without the special flag so that it uses its own toolchain), and try again to adapt my code to it, rather than the other way around.

At this point in the process, I configured CMake to build my extension project as a static library (libsrtp.a) instead of a shared object (libsrtp.so). Static libraries require less linking, and so my goal was just to distill everything down to just compilation. If I could get through that with a custom toolchain, I could worry about the added linking issues later.

Back to Step 3: Build my Extension Code, with a Custom Toolchain.
(Feed that demon whatever CPU cycles he wants.)

For some perspective on what I was about to undertake: The fundamental problem here is that the libwebrtc build is focused on building its own static library and shared object. It isn’t particularly concerned about packaging whatever custom toolchain it used; if you want to use it, then you’ve got to figure that out for yourself. It’s not trying to build that for you, it’s just using it for itself.

Alright, so a hunt commences for all of the custom STL headers in the 492 kajillion include folders spread across the libwebrtrc codebase, and then finding and linking against all of the compiled STL objects. Because there isn’t a convenient static library (.a file), you have to link against all of the object files directly (.o files).

The problem is that although libwebrtc uses a custom version of the LLVM toolchain, it doesn’t use the STL library provided by that toolchain, either. It actually uses a custom, extended version of the STL called Abseil. So just when I thought I had set up CMake to use a custom STL, I still got linking errors; because I had the wrong custom STL.

Now, you may think of this as a rookie mistake. Anyone who’s read up on WebRTC knows that they do all of this custom this and custom that. Fair enough. But even while WebRTC documents how you can build it, they don’t document at all how you can build on top of it. When you professionally program enough in C++, especially in the open source world, you get used to the idea that somebody else takes great care to make sure that C++ projects are generally designed to be extended. This was clearly not the case. No one gave two wits or giggles as to how to make this easy for anyone.

Anyway, back to Abseil. So another day of dickering and I’ve got the right C++ headers, and now the STL object files, and everything is structured in my CMake the way it should be. I’m ready to build my native dummy placeholder implementation sitting in my extension project, just trying to make sure everything compiles and links. Eventually, I get it right (it’s about time!) and things are looking up.

Next step, I revert my CMake back to build a .so instead of a .a, and then my workspace will be ready to start real coding. (When running in Android, you need a .so; having just a .a doesn’t help you.) Just make that simple change, recompile, relink, and all will be good.

By now, I am pretty sure that you’re seeing my pattern of senseless optimism, and are subsequently laughing into your coffee mug brewed with the tears of broken-hearted project managers.

See, now the linker is complaining that the libraries atomic and unwind are missing. Normally, when you build with the NDK, these things are provided as part of the toolchain and always available automatically, much like the Android logging library. Unfortunately, I’m not building with that toolchain, I’m building with the custom toolchain from libwebrtc — and it doesn’t contain CPU-compatible versions of these libraries anywhere. Nowhere.

Sigh. Dead end.

Back to Step 2: Rebuilding libwebrtc with the NDK, or die trying.
(Time to fix Google’s nonsense.)

Previously, I had discarded the option to build libwebrtc using a standard toolchain, because the build had faced errors; and who knew how bad that could be. (Although, if I had known how bad the alternative would be…. well, hindsight is 20/20, as they say.)

After lots of cussing and explaining to my project manager what was going on — a nightmare unto itself that I won’t bore you with, but I’m sure you can imagine — it was time to see if I could fix Google’s broken build.

Thankfully, with my black belt in Google Fu, I was able to find that someone had posted a solution to this back in November of 2022. Kinda hurts knowing that someone solved this, but it never actually got into the mainline codebase.

(Cue the internal screaming.)

A few patched GN files later, I was finally able to rebuild libwebrtc.a for Android 32 with a regular NDK for AARCH 64 ARM v8. I ended up with this GN command for building libwebrtc:

gn gen out/Release --args='is_debug=false is_component_build=false rtc_include_tests=false target_os="android" target_cpu="arm64" use_custom_libcxx=false'

Exhausting. And sadly, not over yet.

Back to Step 3: Build my Extension Code with NDK.
(Hopefully no more nefarious pacts required.)

Working back and forth between my Ubuntu laptop and the client’s Windows PC, I start working through it — until I encounter a bug in the LLVM compiler:

[1/2] Building CXX object CMakeFiles/srtp.dir/fake_frame_encryptor.cpp.o
FAILED: CMakeFiles/srtp.dir/fake_frame_encryptor.cpp.o
...\ndk\25.1.8937393\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=arm-linux-androideabi --sysroot=.../ndk/25.1.8937393/toolchains/llvm/prebuilt/windows-x86_64/sysroot -DATOMIC_LLONG_LOCK_FREE=2 -D_LIBCPP_HAS_THREAD_API_PTHREAD -Dsrtp_EXPORTS -ID:/work/srtp/app/src/main/cpp -ID:/work/srtp/app/src/main/cpp/../../external/headers/webrtc -ID:/work/srtp/app/src/main/cpp/../../external/headers/abseil -isystem .../.gradle/caches/transforms-3/51cb0046d00259ff872b09457dca84a7/transformed/openssl-1.1.1q-beta-1/prefab/modules/crypto/include -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -std=c++17 -stdlib=libc++ -fno-limit-debug-info -fPIC -MD -MT CMakeFiles/srtp.dir/fake_frame_encryptor.cpp.o -MF CMakeFiles\srtp.dir\fake_frame_encryptor.cpp.o.d -o CMakeFiles/srtp.dir/fake_frame_encryptor.cpp.o -c D:/work/srtp/app/src/main/cpp/fake_frame_encryptor.cpp
In file included from D:/work/srtp/app/src/main/cpp/fake_frame_encryptor.cpp:11:
In file included from D:/work/srtp/app/src/main/cpp/api/test/fake_frame_encryptor.h:11:
In file included from D:/work/srtp/app/src/main/cpp/../../external/headers/webrtc/api/array_view.h:14:
In file included from .../ndk/25.1.8937393/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/c++/v1/algorithm:643:
In file included from .../ndk/25.1.8937393/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/c++/v1/memory:673:
  .../ndk/25.1.8937393/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/c++/v1/atomic:2759:16: error: use of undeclared identifier '__libcpp_signed_lock_free'  typedef atomic<__libcpp_signed_lock_free> atomic_signed_lock_free;                 ^  .../ndk/25.1.8937393/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/c++/v1/atomic:2760:16: error: unknown type name '__libcpp_unsigned_lock_free'; did you mean 'atomic_signed_lock_free'?  typedef atomic<__libcpp_unsigned_lock_free> atomic_unsigned_lock_free;                 ^  .../ndk/25.1.8937393/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/c++/v1/atomic:2759:43: note: 'atomic_signed_lock_free' declared here  typedef atomic<__libcpp_signed_lock_free> atomic_signed_lock_free;

That’s right, you heard me, a bug in the LLVM compiler.

I started coding in C++ over thirty years ago, and not once have I ever encountered a bug in the compiler itself. And I even found it reported: https://reviews.llvm.org/D75183

Nightmare 2: Really, a Compiler Bug? REALLY?

Photo by James Kemp on Unsplash

By now, Android Studio was being a pain, and for the sake of simplicity, I migrated building my own libsrtp.so shared object into its own, separate build. (This is also the actual point where I separated out an actual Maven project for the jarfile dependency, as I mentioned above.)

After all kinds of research and mucking around (I’ll spare you the details), I discover that if I upgrade to NDK 26 on Ubuntu, the bug is fixed there. I’m not the biggest fan of Windows to begin with, so I put that aside and do the rest of the job on my Ubuntu laptop. With NDK 26 installed, I rebuild everything again: both libwebrtc and my extension. I can feel my laptop CPU complaining that it wants a raise.

This time around, everything finishes cleanly. Finally, my dummy do-nothing frame encryptor and decryptor produce my libsrtp.so shared object that I have fought so desperately for, and my Android Studio build accepts the .so and my tests at least start. Good signs. I’m past the worst of it. (I hope and pray.)

Elegant? No. Workable? Yes. Finally.

Back to Step 3 for Real: Write my AES256 Implementation.
(Hiccups still ahead, but at least I’m out of the underworld.)

My simple plan was to implement the native interfaces and perform the actual cryptographic operations with a preexisting library. I started off figuring that I could do all of this neatly and cleanly in Android Studio, since at this point I had what I needed, right? (Narrator: “In fact, he was wrong.”)

Early on, my assumption was that I could just use a prefab OpenSSL dependency, and then just use the OpenSSL API in C++. I’ve been using the OpenSSL C++ API since 2004; should be easy enough.

Unfortunately, that generated a trillion linking errors. It didn’t take long before I understood that WebRTC includes BoringSSL, which includes lots of symbol conflicts with OpenSSL. So I couldn’t use an OpenSSL prefab; instead I needed to use BoringSSL. That meant I would have to download it and build it myself.

Back to Steps 1 & 2: Getting & Building the Code.
(BoringSSL this time.)

Thankfully, this was pretty straightforward. With a simple Git clone call, I had what I needed. Building it was similarly straightforward, and now I had generated a libcrypto.so dependency I could rely on in my extension project. It’s more or less a drop-in for your typical OpenSSL include files and libcrypto.so, so this was blessedly easy considering what I had already been through.

Back to Step 3: Finish my Extension Code.
(S’About time. )

More than anything else, I had to clean up a lot of the mess at this point. Anything related to custom STL or custom toolchains was no longer needed, and things went back to looking more or less as they should.

I kept the Android Studio project for testing, plus it serves as a nice example setup for how to use this library. You can find everything here so that you don’t need to suffer the same way I did. Everything ready for you to incorporate directly into your existing Android WebRTC project.

Elegant? Ultimately: maybe? Workable? Definitely yes.

Photo by Aaron Burden on Unsplash

When Baruch Speiser is not busy being the geek that other geeks come to with their geek problems, he enjoys reading, woodworking, and reading to his kids. You can find him on LinkedIn here.

--

--

Baruch Speiser

CTO of Cambium, Applicable Innovation (https://cambium.co.il). Long-time Java Architect and hobbyist woodworker. https://github.com/blspeiser