How I Crafted my audio (looping) library: JVM meets native

Mikołaj Lemański
CodeX
Published in
3 min readJun 6, 2024

Each tool is designed for a specific purpose, and it’s essential to select the one that aligns best with the task at hand. With the advent of AI assistants, leveraging unfamiliar yet efficient tools has become more accessible than ever. So why not use them?

In my previous story I have discussed the overall architecture of my audio looping library. Today I will like to share a insight on how did I implemented the JVM (Android) to native interface and what mistakes did I make along the way.

The JVM

First of all, let’s talk about the JVM. It is great and keeps getting better with interesting projects such as Project Panama, which will make it even cooler by improving the connection between Java and native libraries. However, there is a difference between the well-known JVM and the Android JVM.

The Android JVM, known as Dalvik (and its successor, ART), uses a different approach compared to the standard JVM. Android applications are compiled into DEX (Dalvik Executable) files instead of Java bytecode. These DEX files are optimized for running on mobile devices. This means that certain features available in the standard JVM may not be directly applicable or available in the Android JVM.

So in Android we are somewhat limited on the use of latest and greatest JVM features. It is not ideal but in last couple years Google has made a big lep from Java 8 to Java 17 on Android and I hope that in near future we will see the Java 21 introduced.

JNA and JNI

Although we do not have access to Project Panama (yet!) there are couple of ways to acheive the JVM-to-C interop. The one that I have decided to go with at first is JNA. (Java Native Access). JNA is a library that provides Java programs easy access to native shared libraries without writing anything but a simple Java interface. It is straightforward to set up:

  • add the library to your project (if on Android make sure to use the AAR version),
  • write an interface for the library

You’re done! Quick and simple, but there’s a catch — JNA is slow. Compared to JNI (Java Native Interface) this library is much less performant and also larger in size. There are many benchmarks on the internet that prove that and I can also tell from my own experience. But JNA was created with development speed in mind rather than performance. JNA is great piece of work and I am sure there is nothing better for fast prototyping and quickly changing codebases. It is like every tool. It has it’s purpouse and it serves well if used correctly. I’ve decided to use JNA at first stages of my work because it adapts good to fast paced development. However from the beginning my plan was to switch to JNI once my library API reaches minimum stability.

The switch with SWIG

The faster (in terms of performance) and supported by Android Studio way is to use JNI. It is the traditional way of interfacing Java with native code and is supported by Android Studio.

JNI requires more setup than JNA. You need to load a library and write interface wrapper files in C that use the jni.h library. And that is where the fun begins. Those interface files can get very messy and are tricky to implement by hand if you have no prior experience with JNI.

But as always there is no need to make it hard for yourself. Just use the tool.

SWIG connects programs written in C and C++ with various high-level programming languages, including Java. It generates the JNI wrapper code automatically, which simplifies the process significantly.

There are many tutorials on how to integrate SWIG with Android project but most of them are quite dated. To save the SWIG knowledge from getting forgotten I’ve decided to write a quick tutorial on how to integrate SWIG with modern Android project. If you are interested check it out here.

--

--

Mikołaj Lemański
CodeX
Writer for

Programmer and musician blending tech and creativity. Medium is my personal space, where I share insights in hopes that others will find them useful.