QLabKit is an Objective-C library for controlling QLab over the OSC API in QLab 3 or later. QLabKit requires macOS 11+ or iOS 15+.
NOTE: This library is under active development and the API may change.
All the files for the library are in the lib folder. Copy all the files from that folder into your project. Make sure you also include the code in the F53OSC folder which is a submodule. You'll also need to link against Security.framework. All files in QLabKit and F53OSC use ARC.
QLabKit can also be installed on iOS using CocoaPods by adding the following to your podfile:
pod 'F53OSC', :git => 'https://github.com/Figure53/F53OSC.git'
pod 'QLabKit', :git => 'https://github.com/Figure53/QLabKit.objc.git'There are four primary classes you will use for talking to QLab:
QLKBrowser- automatically discover QLab instances on the networkQLKServer- represents an individual QLab server with a name, host, and portQLKWorkspace- a single workspace on a serverQLKCue- a simplified representation of a cue. A cue list cue is also represented as a cue
There are other classes in QLabKit that these classes rely on that you need not worry about. Read the headers of these primary classes for more usage information. All classes in QLabKit use ARC.
The first thing you need to do is to get a QLKWorkspace instance to communicate with a single workspace from QLab. You can get this in one of two ways:
QLab advertises itself using Bonjour. This allows for the automatic discovery of all QLab machines on the same local network. The QLKBrowser class handles this for you like so:
Create a browser object and give it a delegate that implements QLKBrowserDelegate protocol:
QLKBrowser *browser = [[QLKBrowser alloc] init];
browser.delegate = self;
[browser start];
// Optional: continuously refresh every 5 seconds
[browser enableAutoRefreshWithInterval:5];Implement the required QLKBrowserDelegate methods. The browser has a servers property that is an array of QLKServer objects. Each QLKServer has a workspaces property that holds an array of QLKWorkspace objects discovered on the network.
- (void) browserDidUpdateServers:(QLKBrowser *)browser
{
// Browser has a servers property
for ( QLKServer *aServer in browser.servers )
{
for ( QLKWorkspace *aWorkspace in aServer.workspaces )
{
// do something with the servers and workspaces, i.e. add to a selection UI, etc
}
}
}NOTE: As of iOS 14, your app must be granted permission by the user to connect to devices on the local network. To enable this, your Info.plist must include the NSLocalNetworkUsageDescription key with a description of your app's network usage and the NSBonjourServices key with the QLab Bonjour service value _qlab._tcp. For example:
<key>NSLocalNetworkUsageDescription</key>
<string>Some descriptive text explaining your app's reason to connect to the local network.</string>
<key>NSBonjourServices</key>
<array>
<string>_qlab._tcp</string>
</array>
If you don't want to automatically discover QLab, you can also do it manually by first creating a server:
NSString *hostIP = @"10.0.1.1";
NSInteger port = 53000;
QLKServer *server = [[QLKServer alloc] initWithHost:hostIP port:port];
[server refreshWorkspacesWithCompletion:^(NSArray<QLKWorkspace *> * _Nonnull workspaces) {
// server now has workspaces
for ( QLKWorkspace *aWorkspace in workspaces )
{
// ... do something with aWorkspace
}
}];
Once you have a workspace, you can send commands to and get data from QLab. The first thing is to connect to the workspace:
QLKWorkspace *workspace; // assume this exists as a result of one of the earlier methods
// Connect to workspace
NSString *passcode = ...
[workspace connectWithPasscode:passcode completion:nil];
// Tell workspace to GO
[workspace go];
...
// Update name of a cue, assuming you have a cue object
cue.name = @"New name";QLKWorkspace exposes higher level methods so you don't have to directly deal with formatting the correct message and address. However, there may be API calls that the workspace class doesn't currently support, and you can use the lower-level methods to manually send a message.
NSString *address = [NSString stringWithFormat:@"/workspace/%@/cue_id/%@/name", workspace.uniqueID, cue.uid];
[workspace sendMessage:@"New Name" toAddress:address];There is also working demo project that shows how you might hook all of this together to find servers on the network, show their workspaces, connect to a workspace, and finally fetch and display all the cues. Open QLabKit.xcodeproj and run the QLabKitDemo project to learn more.
Requires macOS 11+ or iOS 15+.
- Additional support for QLab 5.1 - 5.5.
- Network socket background queues are now created with a QOS class.
- Fixed the names of methods
-sendMessagesWithArguments:toAddress:,-sendMessagesWithArguments:toAddress:block:, and-sendMessagesWithArguments:toAddress:workspace:block:to be singular (aka-sendMessage...) to match their behavior. - Optimized
workspacePrefix:- QLKClientDelegate method
-workspaceSettingsUpdated:is replaced with-workspaceSettingsUpdated:key:arguments:for more granular handling of certain workspace settings update messages. - Removes QLKClientDelegate method
-workspaceIDForClient:in favor of QLKWorkspace setting its workspace ID with new methodsetWorkspaceID:and caching the prefix string. - Removes the duplicate QLKWorkspace
workspacePrefixproperty. - Removes QLKMessage method
-addressWithoutWorkspace:in favor of QLKClient trimming the prefix where needed in-processMessage:.
- QLKClientDelegate method
isWorkspaceSettingsUpdatenow matches a message with at least 5addressPartsinstead of exactly 5.
- Fixes handling the "No passcode" passcode (empty-string) when connecting to QLab v5.
- Adds several convenience methods for getting cue lists and parent cues.
- Adds the
audioOutputPatchDictsproperty which contains the reply payload from/settings/audio/patchListwhen connected to v5+. Use new QLKWorkpace methodaudioOutputPatchDictWithUniqueID:to get a dictionary of values for a given audio output patch ID. This property is kept up-to-date by the workspace in response to Audio settings update notifications. - Adds the
audioMapDictsproperty which contains the reply payload from/settings/audio/mapswhen connected to v5.5+. Use new QLKWorkpace methodaudioMapDictWithUniqueID:to get a dictionary of values for a given audio map ID. This property is kept up-to-date by the workspace in response to Audio settings update notifications. - Renames
surfaceDictForSurfaceID:tosurfaceDictWithSurfaceID:andstageDictForStageID:tostageDictWithStageID:for consistency. The original method names are deprecated and will be removed in a future update. QLKWorkspaceDidUpdateSettingsNotificationnotifications are now posted without coalescing due to the multiple possibleuserInfodictionary values that might accompany a given notification.
- Adds convenience
deferFetchingPropertiesandresumeFetchingProperties. - Fixes duplicate KVO will/did change notifications for the
ignoreUpdatesandworkspacekeys. - Refactors
updateChildCuesWithPropertiesArray:removeUnused:slightly to removeatomicproperties previously mutated on multiple threads. - NOTE:
enqueueCueUpdatedNotificationis now expected to be called only from the main thread.
Requires macOS 11+ or iOS 15+.
- Adds support for connecting to QLab v5. See
-[QLKWorkspace connectWithPasscode:completion:]and the QLab OSC dictionary for more. - Adds support for unified code formatting of QLabKit source code using clang-format.
- GLKit.framework is no longer a required dependency (deprecated by Apple in macOS 10.15 and iOS 13). Use new type
QLKQuaternionto replaceGLKQuaternion. - CocoaLumberjack is no longer added as a dependency when building with CocoaPods. It is unneeded since the socket classes that include CocoaLumberjack
DDLog.hhave logging disabled by default.
QLKMessageHandlerBlockis replaced withQLKMessageReplyBlock, which adds astatusparameter. Note that thedataparameter is now properly annotated as nullable.- The string values of certain video geometry keys are updated for compatibility with QLab v5.0 and later. For legacy values when connecting to QLab v3 or v4, use the constants that begin with
QLKOSCV4*. QLKCue.h includes compatibility macros for synonomous keys across multiple versions of QLab.
- Delegate methods are renamed to include the
QLKClientobject as a parameter. - Adds
shouldEncryptConnectionsForClient:to optionally enable an encrypted OSC connection when connected to QLab v5.0 and later.
- Adds
liveColorconvenience getter to fetch the v5 live cue color. - Adds
auditionPreviewconvenience method. Requires QLab v5.0 or later. - The QLKImage property
iconis replaced with NSStringiconName. This avoids loading an image for each QLKCue object created. Instead, a string suitable for passing toimageNamed:is cached, and the image is only loaded when the image file is needed. As such, the #defineQLKImageis no longer needed and is removed. - The
userInfodictionary for theQLKCueListDidChangePlaybackPositionIDNotificationnow includes the unique ID(s) of the old and/or new playback position cues. TheNSKeyValueChangeOldKeyentry, if present, contains theuniqueIDstring of the previous playback position cue. TheNSKeyValueChangeNewKeyentry, if present, contains theuniqueIDstring of the current playback position cue. - Patches in QLab 5 are greatly expanded. They have more descriptive patch list OSC getter names (i.e. not just
/patchList) and are now methods of the respective settings that manage a given patch type. As such, thepatchNamegetter and@"patchDescription"helper insidepropertyForKey:no longer cover enough cases to be useful and have been removed. Going forward when connecting to QLab 5, get the patch index or patch unique ID from the cue and cross-reference with the patch list fetched from the appropriate settings. For backward compatibility with QLab 3 and 4, get both the patch index and patch list from the cue and cross-reference with each other.
- This class is deprecated and will be removed in a future release in favor of using
QLKVersionNumber.
- Adds a new class and NSString category used to compare version number strings.
- The
compare:method of this class compares the "build" number of each version if needed. Use theQLKVersionNumbermethodcompare:ignoreBuild:to optionally ignore the build number when comparing two versions.
- Adds
auditionGoandauditionPreviewCue:convenience methods. Both require QLab v5.0 or later. - Adds a
QLKWorkspaceDidUpdateLiveFadePreviewNotificationwhich is posted by the QLKWorkspace implementation of QLKClientDelegate methodclientLiveFadePreviewUpdated:when connected to QLab 5.4 or later. - When connected to QLab v4 and later, calling
fetchDisplayAndGeometryForCue:no longer fetches properties related to the list of workspace video outputs or properties of a given output. Instead, the workspace populates itsvideoOutputsListproperty with the reply payload from/settings/video/stages(v5.0+) or/settings/video/surfaces(v4.x). This avoids duplicate and/or stale data from being stored in all video cues. Use new QLKWorkpace methodsstageDictForStageID:(v5.0+) orsurfaceDictForSurfaceID:(v4.x) to get a dictionary of values for that video output ID. ThevideoOutputsListarray is kept up-to-date by the workspace in response to Video settings update notifications. - The helper method
addressForWildcardNumber:action:is deprecated because it is unused in QLabKit and only generates/cue/*-prefixed addresses, whereas wildcards can be also be used in addresses with the/cue_id/*prefix.
Requires macOS 10.9+ or iOS 8.4+.
- Fixes the class method
cueTypeIsAudio:so that it now correctly returnsNOfor the following cue types: Fade, Camera, Text/Titles. - Fixes
panicCue:so that theQLKOSCIsPanickingKeyproperty is only updated when connected to QLab 4.0 or later (which is the minimum QLab version that supports the/isPanickingOSC method). - Adds convenience getters
isOverridden,isBroken,isTailingOut, andisPanickingwhich also take into account the property values of child cues in Group, Cue List, and Cue Cart cues. - When using
propertyForKey:to get the quaternion of a Video or Fade cue, the value is no longer transformed to NSValue and is now returned as an array of NSNumbers (representing the X, Y, Z, and W components of the quaternion). The convenience propertyquaternionremains unchanged and gets/sets aGLKQuaternionstruct, and the new convenience settersetQuaternion:tellQLab:also accepts aGLKQuaternionstruct.
- Colors and colorspaces are now more consistent between iOS and macOS.
- The
nameproperty and the class method+[QLKColor colorWithName:]now return an empty QLKColor object for undefined color names. Subclasses or categories can override thenameproperty to define additional colors.
- Fixes an issue where replies from individual OSC getter methods (i.e. calls from
cue:valueForKey:block:) were not being processed. - The internal F53OSCClient used by QLKClient now performs its TCP/UDP communication with QLab on a background thread. F53OSCClient ensures that its F53OSCClientDelegate methods continue to be called on the main thread. However, be aware that custom implementations of GCDAsyncSocketDelegate or GCDAsyncUdpSocketDelegate methods in any subclasses of QLKClient or F53OSCClient will now be called on a background thread and must dispatch back to the main thread when necessary.
- Adds QLKClientDelegate methods:
workspaceDisconnected(required) which is now called when a QLKClient receives an OSC/update/workspace/{id}/disconnectmessage from QLab. This replaces the previous behavior in whichclientConnectionErrorOccurredwas called. This new delegate method now makes it possible for a client app to distinguish between the QLab workspace proactively notifying the client it should disconnect (e.g. because the QLab workspace was closed) and some other issue with the network connection. Connection errors continue to trigger a call toclientConnectionErrorOccurred.clientShouldDisconnectOnError(optional) - If the delegate implements this method and returnsNO, the QLKClient will no longer immediately disconnect after a connection error is reported by its internal F53OSCClient. Instead, the delegate is responsible for disconnecting and tearing down the client at some point in the future. If this method returnsYESor is not implemented, the QLKClient will behave as before and immediately calldisconnectin response to a connection error.lightDashboardUpdated:(optional) - When connected to QLab 4.2 or later, this notifies the delegate when the state of the Light Dashboard has updated.preferencesUpdated:(optional) - When connected to QLab 4.2 or later, this notifies the delegate when certain application preferences in QLab are updated, namelyliveFadePreview. To respond to changes made to workspace-level settings, continue to useworkspaceSettingsUpdated:.
- QLKWorkspace now posts a
QLKWorkspaceDidDisconnectNotificationonly after receiving an affirmative/disconnectupdate message from QLab. QLKWorkspace also no longer posts a redundantQLKWorkspaceDidDisconnectNotificationwhen disconnecting itself from QLab. All other connection errors, e.g. failed attempts to connect due to an incorrect OSC passcode or other network problems, post aQLKWorkspaceConnectionErrorNotificationso that observers can evaluate whether to attempt to reconnect or not. - The
connectmethod is deprecated because it does not support connecting to workspaces with an OSC passcode. Instead, useconnectWithPasscode:completion:and passnilfor the passcode parameter to connect to a workspace whosehasPasscodeproperty isNO. - The method
connectWithPasscode:completion:now caches the passcode in the workspace only upon a successful connection. - Adds a property
attemptToReconnectwhich QLKWorkspace uses in its implementation of the new QLKClientDelegate methodclientShouldDisconnectOnError. After receiving a connection error notification, QLKWorkspace uses the value of theattemptToReconnectproperty to determine whether to attempt to reestablish a connection to the current workspace or to disconnect immediately. - The methods
startHeartbeatandstopHeartbeatare now public and can be used to actively monitor the network connection. When the heartbeat is running, a network timeout will cause the workspace to post aQLKWorkspaceConnectionErrorNotification. - Adds two new methods
deferFetchingPropertiesForCue:andresumeFetchingPropertiesForCue:which can be used to reduce network traffic and significantly improve performance when connected to large workspaces. Selective use of these methods allows a workspace to consolidate update requests on a cue-by-cue basis, enabling a client app to send requests for data only when it is actually needed (e.g. when a cue is about to become visible in the UI). When a workspace is set to defer fetching the properties of a given cue, all QLKWorkspace methods prefixed withfetchwill cache the property key(s) from any request for that cue instead of sending an OSC message to QLab. When the workspace later is set to resume fetching the properties for that cue, a single/valuesForKeysmessage will be sent to QLab requesting values for all previously-cached property keys, and allfetchmethods will once again transmit OSC requests for that cue immediately when called. - Adds a property
defaultDeferFetchingPropertiesForNewCues. Set this property toYESto cause the workspace to defer fetching properties for all new cues immediately upon creation. For example, this can be used to avoid flooding the network with OSC update requests when first connecting to QLab. The default for this property isNO, meaning new cues created by the workspace will not defer fetching properties (the "resume" behavior). - Adds a
QLKWorkspaceDidUpdateLightDashboardNotificationwhich is posted by the QLKWorkspace implementation of QLKClientDelegate methodlightDashboardUpdated:when connected to QLab 4.2 or later. - Adds a
QLKQLabDidUpdatePreferencesNotificationwhich is posted by the QLKWorkspace implementation of QLKClientDelegate methodpreferencesUpdated:when connected to QLab 4.2 or later. - The methods
fetchChildrenForCue:block:andfetchAudioLevelsForCue:block:are deprecated because theirblockparameters are not compatible with the new deferred property fetching mechanism. Instead, request these values usingcue:valueForKey:block:with the keyschildrenandsliderLevels, respectively. - The values of the following NSString constants are updated to follow the convention of the value matching the name. Any code that directly accesses the value of one of these constants, e.g. comparing to another string using
isEqual:orisEqualToString:, should update to use the new string values:QLKWorkspaceDidConnectNotificationQLKWorkspaceDidDisconnectNotificationQLKWorkspaceConnectionErrorNotification
Requires macOS 10.9+ or iOS 8.4+.
- The QLKBrowserDelegate method
serverDidUpdateWorkspaces:is renamed tobrowserServerDidUpdateWorkspaces:to avoid collision with the QLKServerDelegate method of the same name. - The selector called by the NSTimer scheduled in
enableAutoRefreshWithInterval:is changed from the public methodrefreshAllWorkspacesto a new private method_refreshAllWorkspaces:.
- Color values are updated to match the color scheme of QLab 4.
- Helper class methods
colorWithRed:green:blue:alpha:andcolorWithWhite:alpha:are deprecated in favor of specific values for NSColor/UIColor for better color matching between Mac and iOS. - The "type" property for the object returned by class method
defaultColornow has the string value "default" instead of "none". startColorandendColorare deprecated since QLab 4 no longer displays cue colors with gradients. UselightColoranddarkColorinstead.lightBlueColor,panelColorandnavBarColorare no longer used in QLab 4 and are deprecated.
playbackPositionUpdated:is changed tocueListUpdated:withPlaybackPositionID:to allow updating the playback position individually for each cue list cue.
- Class method
iconForType:now returns the string value "mic" for Mic cues to match QLab conventions. pushUpProperty:forKey:is deprecated. UsesetProperty:forKey:tellQLab:instead, with thetellQLabparameter set toYES.triggerPushDownPropertyForKey:is deprecated. UsepullDownPropertyForKey:block:instead.pushDownProperty:forKey:is deprecated. UsesetProperty:forKey:tellQLab:instead.- String constant
QLKCueHasNewDataNotificationis removed because the method which posted this notification is now deprecated. - The unique ID of each cue list cue's playback position can now be accessed using the
playbackPositionIDproperty and set usingsetPlaybackPositionID:tellQLab:. View controllers should now observeQLKCueListDidChangePlaybackPositionIDNotificationnotifications to respond to playback position changes on a per-cue list basis. - QLKCue property getters and setters are now thread-safe and updates are processed on a background queue.
QLKActiveCueListIdentifieris renamed toQLKActiveCuesIdentifierfor clarity.QLKCueTypeMicrophoneis renamed toQLKCueTypeMicto match QLab conventions.
- The property
browseris removed. QLKBrowser now conforms toQLKServerProtocolso an existing browser instance can now be set as the delegate of QLKServer instead of needing to have a dedicated browser property on the server itself.
uniqueIdproperty is renamed touniqueIDto unify capitalization of "ID".fetchMainPropertiesForCue:is renamed tofetchDefaultCueListPropertiesForCue:.- A
QLKCueUpdatedNotificationnotification is now posted only when cue data has actually changed. - String constant
QLKWorkspaceDidChangePlaybackPositionNotificationis replaced byQLKCueListDidChangePlaybackPositionIDNotification. (See QLKCue above.) - String constant
QLKWorkspaceDidUpdateCuesNotificationhas been removed and is replaced withQLKCueUpdatedNotification. Observers ofQLKCueUpdatedNotificationnotifications can now inspect the notification object, which is the cue that was updated, and react accordingly. For example, the notification object will be the QLKWorkspacerootafter adding a cue list to the workspace. Test the notification object cue forisCueListto determine if the child cues of a particular cue list have changed. - All method parameters of type
QLKMessageHandlerBlockare renamed to "block" to distinguish from the various styles of other "completion" blocks:cue:valueForKey:completion:is renamed tocue:valueForKey:block:.fetchCueListsWithCompletion:is renamed tofetchCueListsWithBlock:.fetchPlaybackPositionForCue:completion:is renamed tofetchPlaybackPositionForCue:block:.fetchChildrenForCue:completion:is renamed tofetchChildrenForCue:block:.fetchAudioLevelsForCue:completion:is renamed tofetchAudioLevelsForCue:block:.
- The "type" property for the
__root__and__active__cue list cues are changed fromQLKCueTypeGrouptoQLKCueTypeCueList.
QLabKit © copyright 2014-2025 Figure 53, LLC.
QLabKit is licensed under the MIT license.