The following sections on this page describe the key parts in brief form, about how to add support for JACK to an iOS application. It is directed to developers who have never actively been using JACK before. It helps you getting your JACK app working in a reasonable short time. It does not cover all possibilities of the JACK API in full extent. For more advanced purposes, please browse the more detailed sections of this JACK API documentation.

Xcode Project Setup

You should first download the latest version of the JACK iOS SDK and extract it to some arbitrary place on your Mac. Then drag jack.framework into your iOS app's Xcode project and make sure the audio background mode is enabled in your app's Info.plist file:

The call above usually just might fail because of the 2 reasons shown.

The official JACK (server) app must be running, since it not only provides the control GUI of the JACK system, but also the JACK server. We recommend you, to simply call jack_client_open() on app start, and in case it succeeds, initialize your app for using JACK. If the call fails, initialize your app to use your usual audio/MIDI system like the CoreAudio/CoreMIDI API. This way end users don't have to configure your app explicitly. Keep in mind the end user might start quite a bunch of JACK client apps!

Please also check for the JackVersionError flag on iOS, and i.e. prompt the user a message box in this case. Reason for the JackVersionError flag is the fact, that you have to statically link the JACK client library into your app binary on iOS (Apple does not allow DLLs for App Store Apps at this point). So the JACK library you linked now, might become incompatible to a future version of JACK. We took precautions that this case should not happen in any time soon. It might happen one day though, however it will most probably just require that you download the latest version of the JACK SDK and rebuild your app.

Usually one only creates one JACK client per app. However you are free to create even more, individual JACK clients for one app. For example for rather complex DAW apps with several integrated soft sequencers and effects, you might expose parts of your app as separate JACK clients.

In the rare case you want your own CoreAudio code rendering/capturing code to remain active for some reason, while using JACK at the same time in the same app, you should pass JackNoBackground to jack_client_open(). Reason: the JACK client framework automatically runs a fake CoreAudio mechanism to actually enable your app to remain active in the background, which would in that very special case cause a conflict.

Publish client icon

To show an appropriate icon for your app on the "Client Map" screen of JACK (server) app, use the following Objective C code:

Adjust "Icon-Metro136" to the actual name of your icon image file (PNG format expected at this point). And make sure that icon file is added to your Xcode project. Currently icons on the "Client Map" of the JACK (server) app are shown with a resolution of 136x136px on Retina displays. If the icon you provide has a different resolution, it will be scaled to the appropriate resolution. You may replace the Objective C code above of course by any other means. The relevant part is only the jack_custom_publish_data() call, which actually transmits the PNG icon as raw data buffer to the JACK server. The key name "icon.png" is mandatory on this call. If you use another name, it will not appear on the JACK GUI.

Register callback functions

Next you should register your callback functions which JACK should call for various purposes. At least you need to call jack_set_process_callback() to register a function written by you, that will handle audio and/or MIDI processing. The following example demonstrates the common part of processing audio & MIDI with JACK:

Each audio port in JACK is a mono audio channel in 32 bit float format. The argument nframes of the process callback is an integer type variable, which reflects the amount of frames (or "sample points") to be processed in the current period. So assuming your app would just want to write "silence" to the output ports, it could look like this:

Which would neither be efficient nor useful for anything, however this is just about giving you an intuitive, compact idea about how to write your audio code for it.

MIDI events in JACK are simply raw MIDI data buffers along with a time stamp, see jack_midi_event for more details about it.

Note

The code in the supplied "process" function must be suitable for real-time execution. That means that it cannot call functions that might block for a long time. This includes any function that directly or indirectly allocate or deallocate memory like malloc(), free(), printf(), as well as common blocking synchronization functions as pthread_mutex_lock(), sleep(), wait(), poll(), select(), pthread_join(), pthread_cond_wait(), as well as any Objective-C method, throwing of C++ Exceptions, etc. The JACK server carefully monitors the timing of each client, and removes a client automatically from the audio execution graph in case it misses to return from the process callback within the expected time frame of the currently selected latency setting of JACK, to prevent one single JACK client application to tear down the whole JACK system.

Then actually register the callback functions you just implemented with:

There are various other callback functions which you might register. For example for reacting when essential system parameters have been changed like sample rate, latency (buffer size) and much more. A list of the most important JACK callbacks can be found at Setting Client Callbacks.

Activate client

If this call succeeds, your callback functions will now periodically be called to let your app process audio & MIDI data. Please note, that after this call, no more callback functions can be registered. If you really need to register additional callbacks after this point for some reason, you might do so by suspending your JACK client for a moment with jack_deactivate(), add your callback functions, and reactivate your JACK client with jack_activate().

Close client on exit

When your application exits, or when you want to switch from JACK mode to i.e a native CoreAudio mode in your app at some point, then close your JACK client with:

This will automatically destroy all the ports, data, connections and everything created and established previously for the client.

Please note, if the JACK server closes your client, your JACK client will not be freed. You have to call jack_client_close() on your own to free the resources allocated for your client by dispatching it in your JACK shutdown callback as already shown above. You would dispatch it in the shutdown callback, since it is not valid to call jack_client_close() in the context (thread) of the shutdown callback. We recommend to also ensure freeing your client's resources in your app delegate's termination handler:

Freeing your client resources is so important, because it would otherwise leak system resources, which would even remain leaked after your app terminated.

Remote App Start

The JACK control app provides a very important feature from user aspect: the ability to launch JACK client apps directly from the JACK (server) app and fast switching the screen between the various JACK apps, without forcing the user to do such things with home button and iOS desktop.

To support these important features, you need to add an URL schema entry to your app's Info.plist file.

It is important here that you choose an unique URL schema, which is not already been used by another iOS app. So preferably make the URL schema name i.e. a combination of your company's name and your app's name, which was i.e. foocompanymyapp in the example above.

We also recommend you to call jack_app_register() each time your app launches. For example in the following method of your app delegate.

This call checks whether your app is already been "known" to the local JACK installation. If not, it will inform the JACK installation about the existence of your app, so that your app appears in the list of installed JACK apps and accordingly to allow the user to start your app directly within the JACK control app.

You can check the launchOptions argument of that app delegate method shown above, for finding out whether your app was launched regularly from the iOS desktop or by JACK instead:

which will immediately bring the JACK (server) app into foreground on the screen. You might even use the same function with your own JACK client name instead to bring your own app into foreground, i.e. to inform the user about some very important occurrence in your app while the user is currently watching at another app. However we discourage to use jack_gui_switch_to_client() to bring your own app "unasked" into foreground. It might make sense under very, very rare and really important circumstances. But in doubt, don't use the function for that purpose. Because otherwise it could end up your app being very annoying to the user, causing more damage to the user experience instead of improving it.

Note

You need to build your app with JACK iOS SDK 1.9.10.2 or higher for the remote app start and screen switching features.

That's it!

You should now be able to compile your app with JACK support in Xcode.

Note that the main JACK (server) app is not dictating. You can also connect and disconnect between any foreign apps from your own app, which is pretty simple, for example:

So it's just CLIENT_NAME:PORT_NAME as argument. Same functions for Audio and MIDI connections. So you could also implement something like the "Jack Clients" screen in your own app. You can even adjust JACK system wide parameters like latency (buffer size) which effect the entire JACK system.