JACK Seniors Table of ContentsShort summary of JACK iOS differences for experienced JACK developers. This page is a short summary for developers who are already familiar with developing with the JACK API on other operating systems. It is dedicated to summarize the key differences between this iOS version of the JACK API compared to the one you are used to from other systems. There were quite some complications to bring JACK on iOS. On one hand technical issues, since iOS is a very constraint environment, and licensing issues on the other hand, since there are no DLLs allowed for iOS apps being published on the Apple App Store, forcing us to distribute a static libary version of JACK and resolving license implications caused by this. Due to those reasons we were forced to adjust the JACK API for iOS to some extent. Removed API partsThe following parts have been removed from the iOS version of the JACK API:
Added API partsThere was only one new API part been added to the JACK iOS API:
as well as the following additional functions: Linking libjackLike mentioned above, libjack is only available as static library on iOS. 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. The framework contains the static library and the header files. Background ModeOn iOS, apps are by default suspended (by the SpringBoard service) if the app is not in foreground. Since that would destroy the whole concept behind JACK, you need to make sure the audio background mode is enabled in your app's Info.plist file: <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>My App Name</string>
...
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
</dict>
</plist>
This ensures that your app will continue running in the background after the user pressed the home button of the device (actually in conjunction with the automatic CoreAudio mechanisms already handled for you by the JACK library). The coding partExcept of API parts being removed / added to the JACK iOS API, as already explained above, there is only very little you need to know regarding new things on code level. The few ones are enumerated next. Publish client iconTo show an icon for your JACK client on the "Client Map" screen of the JACK (server) app, use the following Objective C code: #include <jack/custom.h>
...
NSString* iconFile = [[NSBundle mainBundle] pathForResource:@"Icon-Metro136" ofType:@"png"];
NSFileHandle* fileHandle = [NSFileHandle fileHandleForReadingAtPath:iconFile];
NSData* data = [fileHandle readDataToEndOfFile];
const void* rawData = [data bytes];
const size_t size = [data length];
jack_custom_publish_data(client, "icon.png", rawData, size);
[fileHandle closeFile];
Adjust Create JACK clientIt is important on iOS that you take care about the JackVersionError result flag. You may handle the jack_client_open() step in iOS apps like suggested below: #include <jack/jack.h>
...
jack_status_t status;
if (!client) {
if (status & JackVersionError)
fprintf(stderr, "App not compatible with running JACK version!\n");
else
fprintf(stderr, "JACK (server) app seems not to be running!\n");
return -1;
}
The call above usually just might fail because of the 2 reasons shown.
You may also use jack_server_installed() to check whether JACK is installed on the device at all, and jack_server_running() to check whether the main JACK (server) app is currently running on the device.
Shutdown CallbackYou should implement a JACK shutdown callback and register it with jack_on_info_shutdown(), like this // Callback for being executed when the JACK (server) app is closing this
// JACK client for some reason. We definitely recommend you to implement
// such a callback for your app.
{
if (code & JackClientKilled) {
// If this flag is set, then your client was closed by the user by
// pressing "X" button of the client icon in the JACK control app.
// In this case you should simply quit your app, since the user
// was already asked in the JACK control app whether he really wants
// close this app.
exit(0);
} else {
// Don't forget to free your JACK client when the JACK shutdown
// callback is triggered, because JACK does *not* do it for you!
dispatch_async(dispatch_get_main_queue() /*GUI Thread*/, ^{
jack_client_close(client);
client = NULL;
});
// ... otherwise if this block is reached, your client might got
// closed because the JACK control app (and with it the server)
// was closed or i.e. when JACK apps created too much CPU load,
// causing the server to sort out some of the clients, to prevent
// the device turning unresponsive. Either quit the app, or show a
// message dialog to the user, asking him if the app can be closed
// (i.e. preventing some unsaved data to get lost) or automatically
// switch your app from JACK mode to i.e. CoreAudio/CoreMIDI mode.
if (code & JackClientZombie) {
// Client was closed because of too much CPU load
} else {
// Possibly (still unknown) reason
}
}
}
You would dispatch jack_client_close() in the shutdown callback, since it is not valid to call jack_client_close() in the context (thread) of the shutdown callback. Be sure to free your client's resources in your app delegate's termination handler: - (void)applicationWillTerminate:(UIApplication *)application
{
if (client) jack_client_close(client);
}
Freeing your client resources is so important, because it would otherwise leak system resources, which would even remain leaked after your app terminated. Note also that calling jack_client_close() is the clean way for an application to be removed from the JACK application graph. Not calling this function would typically cause the server to interrupt the audio stream and result in an audio glitch. Remote App StartThe 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. <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>My App Name</string>
...
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.foocompany.myapp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>foocompanymyapp</string>
</array>
</dict>
</array>
</dict>
</plist>
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. We also recommend you to call jack_app_register() each time your app launches. For example in the following method of your app delegate. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
...
// ensure this app is known by JACK
return YES;
}
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 // was this app launched from the iOS desktop or by some other app?
NSURL* url = [launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];
NSString* src = [launchOptions valueForKey:UIApplicationLaunchOptionsSourceApplicationKey];
NSLog(@"App launched by app '%@' with URL '%@'", src, [url absoluteString]);
You may also provide a button in your app to switch back to the JACK control app. When that button is pressed by the user, simply call jack_gui_switch_to_client() with the following string argument: // bring the JACK control app into foreground on the screen
jack_gui_switch_to_client(client, "jack");
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 bringing an advantage.
That's it!Nothing more to say. Generated by |
|
|