Month: January 2012

Paul Robert Lloyd writes: “As more services require a Facebook account to use them, I wonder if it’s set to become the next Microsoft Windows; a popular piece of software that becomes the only choice available.”

I first read this as “an unpopular piece of software that becomes the only choice available.”

Plenty of people grumble about Facebook. Windows doesn’t seem to have inspired many people to delight when its manufacturer became the biggest company in the world, as Microsoft did in 1998. To me, it feels as if both are unpopular in an emotive sense, despite their ubiquity—though I feel more confident saying that about Windows than Facebook.

But my perspective is probably horribly slanted. Was Windows popular, in its heyday of the late 90s? Popular, that is, in the sense of being widely loved rather than just widely used?

Perhaps it was. I was in the privileged position at the time of being able to look on Windows from a height as a user of Unix workstations and tedious geek blah, so I would never have appreciated its value as a straightforward way of running a personal computer.

Perhaps there were millions of people given liberation and joy by the friendliness and flexibility of Windows, and by its universal availability as a result of its straightforward, resource-friendly design.

M., brandishing new telephone: I find it a bit difficult to actually make phone calls, but it’s great for the internet. No, I really like it. The battery’s hopeless though.

Me: How often do you have to charge it?

M.: About every two days. I thought it was defective at first.

A fun mental exercise is to think of an old product that has been superseded by a newer one, and imagine that their roles are reversed—would you be able to sell anyone the old product as a replacement for the new?

VHS tapes, for example: more intuitive seeking than your old DVD player; no unskippable gubbins at the start; the tape remembers where you’d got up to if you stop and restart; easy to record and re-record on. Very practical!

Awful picture and sound quality though, and much too big. Probably wouldn’t sell all that many, but you’ve at least got the beginnings of a promotional campaign there. You could have a crack at it.

Similarly, DVD looks pretty promising as an improvement over Blu-Ray, being superior in almost every practical detail.

I can imagine trying to flog LP records as an alternative format to digital audio, with quite distinct areas of strength, though I can’t see all that much hope for CDs in between.

Selling your “All-New Feature Phone” as a low-cost, lightweight, miniaturised upgrade for a smartphone would be tricky. Popular new technologies often involve new input methods, and users find it very hard to go back. But if you had to try, you could make a pretty good start by talking about batteries.

Imagine being able to go on holiday for a week or more, and still stay in touch without having to ever worry about finding a charger. That’s what the latest battery management technology exclusive to “Feature Phones” brings you!

The original iPhone reintroduced the sort of comically short battery life familiar to those of us who had mobile phones in 1997 or thereabouts, and since then phones seem to have been going about the same way as laptops did during the 2000s—a series of incremental improvements consumed by incrementally more powerful hardware, meaning we ended the decade with much the same order of magnitude of battery life as we started with.

4. Write JNI function bodies

Our task is to write function bodies for the functions whose declarations have been generated by javah. The first thing we’ll need is a way to get and set the native handles we are storing in each Java class, so that we can keep track of the native object that each Java object corresponds to.

The other does the real work. Here we grab the previously stowed native object from the handle in the Java object, convert the plugin key argument from its opaque jstring type to a C string, call out to the native loadPlugin, and return the result.

When does this delight that finally our superior methods are winning start to wear off?

When does it become a bit of a worry that no other company seems capable of doing this? That we’re probably entering two decades of another closed single-company ecosystem, across a far broader market than the PC market in the 90s? What makes this a good thing? How is it so wonderful exactly? How do you avoid feeling even a little bit queasy about it?

I’m almost grateful for Samsung’s shameless duplication. It feels like without it, there’d be no competition at all.

1. Identify the C++ classes and methods

I’ll initially need to wrap parts of two classes: PluginLoader, in the Vamp::HostExt namespace, and Plugin, in the Vamp namespace.

PluginLoader is a singleton class which loads and returns an instance of a Vamp plugin on request, given the name (or “key”) of the plugin. It’s essentially an object factory.

Then Plugin has both methods that return information about the specific plugin that has been loaded, and methods that are called with blocks of audio data in order to do the actual analysis.

In my first draft, I want to make a singleton Java class to correspond to PluginLoader and implement in it the one method that actually loads the plugin; and I want to make a Plugin class with a couple of the methods that return simple metadata about the plugin.

The methods that do real work involve some complicated return types, so I’ll leave those until later.

So the basic library API I’m starting with looks like this, in the existing C++ API:

The C++ PluginLoader returns a null pointer if it can’t load a plugin. I want to throw an exception instead, and for this reason I haven’t marked loadPlugin as native—instead it will call a native method that returns a null or non-null value, throwing the exception if the returned value is null.

I’ve made other simplifications too. I happen to know that the PluginKey type referred to in the C++ API is just a typedef for std::string, so I’ve translated it to a Java string type for the moment. I’ve omitted the options argument for now as well.

Native object handles

I have two Java classes, each instance of which should “manage” a C++ object of a corresponding class from the native library. Every time a method is called on a given Java instance, it should call through to the same instance of the underlying C++ class.

To make this happen, we need to make the Java object remember which C++ object it is managing.

For this purpose we’ll have both classes simply contain a “handle” field, which will hold a value that (on the native side of the fence) will be interpreted as a pointer to the C++ object on the heap, and (on the Java side) will be an opaque integer value.

We just need to make sure the handle is stored in an integer type big enough for a pointer; the Java long type will do.

Also, we need a way to construct Plugin objects. The PluginLoader will make plugins by calling its native-code implementation, getting back a C++ plugin pointer, and using that to construct our Java Plugin, so our plugin class needs a constructor that works from our opaque handle type.

The initialise method in PluginLoader is there to construct a native object and set up its nativeHandle field. Plugin doesn’t need a similar method, because its handle is given to it in the constructor.

Hang on! How does the native object get deleted? — I give over a later post entirely to discussion of this question, so skip there if you’re interested now.

3. Generate JNI function declarations

For each of the native methods in our Java classes, we need an implementation in the JNI wrapper code. This will be a function in C or C++, with a name encoding the Java class and method name and an appropriate signature to receive the JNI mappings for the Java argument types, and with C linkage.

It’s perfectly possible to write these from scratch, but the JDK includes a tool called javah that can help by producing the function prototypes. It requires compiled class files rather than Java files as input:

The method’s return type, String in the Java code, has been converted to the opaque JNI type jstring.

The function name is an encoding of the package, class, and method name. These must appear exactly as generated by javah, as the JVM relies on them to find the implementation code.

And the two arguments, which are common to all JNI implementation functions, provide the environment object which rolls up the JNI function namespace, and an opaque jobject referring to the this object on which the method was called.

If we leave these headers untouched and simply include them in our implementation files, then we’ll be able to regenerate them when we extend our Java API without losing any of our work.

Administrative note: If you haven’t already, this is a good moment to put the code directory under version control, so as to be able to mess around without fear of losing any working code.

Part 4, the final episode covering a few remaining points of interest.

Java Native Interface, or JNI, is a standard mechanism for calling “native” code—that is, code compiled from a language such as C or C++—from within the Java Virtual Machine.

It allows a programmer working in Java, or another language running on the JVM such as Scala, Clojure, Groovy, or Yeti, to use existing C and C++ library code, for reasons of performance or for compatibility with old or third-party code.

JNI is a bit of an old-school technology, though it’s gained more attention through its use in the Android platform as the glue between managed Dalvik applications and native NDK libraries.

(Later note: Java developers with no C or C++ experience may be happier using JNA, or Java Native Access. This more recent technology uses a single C library for each platform, which is supplied with JNA and which can load any native library. Using JNA still involves writing some boilerplate code, but that code is all in Java. I don’t cover JNA at all in this tutorial.)

What I’m doing

I’m about to make a wrapper for an existing C++ library using JNI, so I’m going to explain the process as I go along.

The library I’m planning to wrap up is the host SDK for Vamp audio analysis plugins[1]. I hope the result will enable Java applications to use these plugins to analyse audio signals.

From a technical perspective, though, it doesn’t really matter what the library is. What matters is that I have some header files that describe the library’s API, and either a DLL or a static library that provides the implementation. In this case I also happen to have the library’s source code, but that isn’t essential to calling it through JNI.

Most JNI tutorials use C as the native implementation language, but here I’m assuming the native code is entirely in C++. (If you’d like to read a simpler introduction that uses C, try the JNI Programmer’s Guide Getting Started chapter.)

This explanation uses desktop Java: although the principles are much the same, I won’t be referring the Android toolchain here.

The steps I need to take

To get my C++ library working from Java code, I will need to:

Identify the C++ classes and methods that I want to make available from those in the library’s API, starting with the smallest subset I can make a meaningful test case from;

Design an appropriate set of equivalent Java classes, in which the methods that will be implemented by the library are declared using the native keyword and left unimplemented in the Java code;

Generate stub function declarations for the JNI wrapper. The wrapper is a chunk of C code that contains a specially named function to implement each of the classes’ native methods, and the generator is what gives us the names of these functions;

Write the body of the JNI wrapper, implementing each function by converting its Java type arguments into appropriate C or C++ types, calling the native library, and converting the results back again;

Make a little test program in Java;

Build everything and test it.

Then repeat until enough of the library has been wrapped.

Next

In the first tutorial post I’ll cover steps 1 to 3, getting to the point where we’re about to have to write some C++ for the JNI wrapper code.

The subsequent post will cover steps 4 to 6, to the point of having a working interface and test program for a simple subset of the C++ library.

And I’ll finish with a couple of posts that discuss management of object disposal and a few other details of handling a more complex method.

[1]To find out more about Vamp plugins, see the programmers’ guide and these tutorials. But although they explain the concepts, note that these describe the process of writing plugins, while we are providing support for hosts— so the APIs are not quite the same.