
! title		Non Session Management API
! author	Jonathan Moore Liles #(email,male@tuxfamily.org)
! revision	Version 1.2
! extra		#(image,logo,icon.png)

-- Table Of Contents

: Non Session Management API

  The Non Session Management API is used by the various components of
  the Non audio production suite to allow any number of independent
  programs to be managed together as part of a logical session (i.e. a
  song). Thus, operations such as loading and saving are synchronized.

  The API comprises a simple Open Sound Control (OSC) based protocol,
  along with some behavioral guidelines, which can easily be
  implemented by various applications.

  The Non project contains an program called `nsmd` which is an
  implementation of the server side of the NSM API. `nsmd` is
  controlled by the `non-session-manager` GUI. However, the same
  server-side API can also be implemented by other session managers
  (such as LADISH), although consistency and robustness will likely
  suffer if non-NSM compliant clients are allowed to participate in a
  session.
  
  The only dependency for client implementations `liblo` (the OSC
  library), which several Linux audio applications already link to or
  plan to link to in the future.

  The aim of this project is to thoroughly define the behavior
  required of clients. This is an area where other attempts at session
  management (LASH and JACK-Session) have failed. Often the difficulty
  with these systems has been not in implementing support for them,
  but in attempting to interpret the confusing, ambiguous, or
  ill-conceived API documentation. For these reasons and more all
  previous attempts at Linux audio session management protocols are
  considered harmful.

  You *WILL* see some unambiguous and emphatic language in this
  document. For the good of the user, these rules are meant to be
  followed and are non-negotiable. If an application does not conform
  to this specification it should be considered broken. Consistency
  across applications under session management is very important for a
  good user experience.

:: Client Behavior Under Session Management

  Most graphical applications make available to the user a common set
  of file operations, typically presented under a File or Project
  menu.

  These are: New, Open, Save, Save As, Close and Quit or Exit.

  The following sub-sections describe how these options should behave when
  the application is part of an NSM session. These rules only apply
  when session management is active (that is, after the `announce`
  handshake described in the #(ref,Non Session Management API::NSM OSC Protocol) section). 
  
  In order to provide a consistent and predictable user experience, it
  is critically important for applications to adhere to these
  guidelines.

::: File Menu

:::: New

  This option may empty\/reset the current file or project (possibly
  after user confirmation). *UNDER NO CIRCUMSTANCES* should it allow
  the user to create a new project\/file in another location.

:::: Open

  This option *MUST* be disabled. 

  The application may, however, elect to implement an option called
  'Import into Session', creates a copy of a file\/project which is
  then saved at the session path provided by NSM.

:::: Save

  This option should behave as normal, saving the current
  file\/project as established by the NSM `open` message.

  *UNDER NO CIRCUMSTANCES* should this option present the user with a
  choice of where to save the file.

:::: Save As

  This option *MUST* be disabled.

  The application may, however, elect to implement an option called
  'Export from Session', which creates a copy of the current
  file\/project which is then saved in a user-specified location
  outside of the session path provided by NSM.

:::: Close (as distinguished from Quit or Exit)
  
  This option *MUST* be disabled unless its meaning is to disconnect
  the application from session management.

:::: Quit or Exit

  This option may behave as normal (possibly asking the user to
  confirm exiting).

::: Data Storage

:::: Internal Files

  All project specific data created by a client *MUST* be stored in
  the per-client storage area provided by NSM. This includes all
  recorded audio and MIDI files, snapshots, etc. Only global
  configuration items, exports, and renders of the project may be
  stored elsewhere (wherever the user specifies).

:::: External Files

  Files required by the project but external to it (typically
  read-only data such as audio samples) *SHOULD* be referenced by
  creating a symbolic link within the assigned session area, and then
  referring to the symlink. This allows sessions to be archived and
  transported simply (e.g. with "tar -h") by tools that have no
  knowledge of the project formats of the various clients in the
  session. The symlinks thus created should, at the very least, be
  named after the files they refer to (some unique component may be
  required to prevent collisions)

> samples/drumbeat-1.wav
> samples/drumbeat-2.wav

:: NSM OSC Protocol

  All message parameters are *REQUIRED*. All messages *MUST* be sent
  from the same socket as the `announce` message, using the
  `lo\_send\_from` method of liblo or its equivalent, as the server uses
  the return addresses to distinguish between clients.

  Clients *MUST* create thier OSC servers using the same protocol
  (UDP,TCP) as found in `NSM\_URL`. liblo is lacking a robust TCP
  implementation at the time of writing, but in the future it may be
  useful.

::: Establishing a Connection

:::: Announce

  At launch, the client *MUST* check the environment for the value of
  `NSM\_URL`. If present, the client *MUST* send the following message
  to the provided address as soon as it is ready to respond to the
  `\/nsm\/client\/open` event:

> /nsm/server/announce s:application_name s:capabilities s:executable_name i:api_version_major i:api_version_minor i:pid

  If `NSM\_URL` is undefined, invalid, or unreachable, then the client
  should proceed assuming that session management is unavailable.

  `api\_version\_major` and `api\_version\_minor` must be the two
  parts of the version number of the NSM API as defined by this
  document.

  Note that if the application intends to register JACK clients,
  `application\_name` *MUST* be the same as the name that would
  normally be passed to `jack\_client\_open`. For example, Non-Mixer
  sends "Non-Mixer" as its `application\_name`. Applications *MUST
  NOT* register their JACK clients until receiving an `open` message;
  the `open` message will provide a unique client name prefix suitable
  for passing to JACK. This is probably the most complex requirement
  of the NSM API, but it isn't difficult to implement, especially if
  the application simply wishes to delay its initialization process
  breifly while awaiting the `announce` reply and
  subsequent `open` message.


  `capabilities` *MUST* be a string containing a colon separated list
  of the special capabilities the client
  possesses. e.g. `:dirty:switch:progress:`

  `executable\_name` *MUST* be the executable name that the program
  was launched with. For C programs, this is simply the value of
  `argv[0]`. Note that hardcoding the name of the program here is not
  the same as using, as the user may have launched the program from a
  script with a different name using exec, or have created a symlink
  to the program. Getting the correct value in scripting languages
  like Python can be more challenging.

// Available Client Capabilities
[[ Name, Description
[[ switch, client is capable of responding to multiple `open` messages without restarting
[[ dirty, client knows when it has unsaved changes
[[ progress, client can send progress updates during time-consuming operations
[[ message, client can send textual status updates 
[[ optional-gui, client has an optional GUI

:::: Response

  The server will respond to the client's `announce` message with the
  following message:

> /reply "/nsm/server/announce" s:message s:name_of_session_manager s:capabilities

  `message` is a welcome message.

  The value of `name\_of\_session\_manager` will depend on the
  implementation of the NSM server. It might say "Non Session
  Manager", or it might say "LADISH". This is for display to the user.

  `capabilities` will be a string containing a colon separated list of
  special server capabilities.

  Presently, the server `capabilities` are:

// Available Server Capabilities
[[ Name, Description
[[ server-control, client-to-server control
[[ broadcast, server responds to /nsm/server/broadcast message
[[ optional-gui, server responds to optional-gui messages--if this capability is not present then clients with optional-guis MUST always keep them visible

  A client should not consider itself to be under session management
  until it receives this response. For example, the Non applications
  activate their "SM" blinkers at this time.

  If there is an error, a reply of the following form will be sent to
  the client:

> /error "/nsm/server/announce" i:error_code s:error_message

  The following table defines possible values of `error\_code`:

// Response codes
[[ Code, Meaning
[[ ERR_GENERAL, General Error
[[ ERR_INCOMPATIBLE_API, Incompatible API version
[[ ERR_BLACKLISTED, Client has been blacklisted.

::: Server to Client Control Messages

  Compliant clients *MUST* accept the client control messages
  described in this section. All client control messages *REQUIRE* a
  response. Responses *MUST* be delivered back to the sender (NSM)
  from the same socket used by the client in its `announce` message
  (by using `lo\_send\_from`) *AFTER* the action has been completed or
  if an error is encountered. The required response is described in
  the subsection for each message.

  If there is an error and the action cannot be completed, then
  `error\_code` *MUST* be set to a valid error code (see #(ref,Non Session Management API::NSM OSC Protocol::Error Code Definitions))
  and `message` to a string describing the problem (suitable
  for display to the user).

  The reply can take one of the following two forms, where `path` *MUST* be
  the path of the message being replied to (e.g. "/nsm\/client\/save"):

> /reply s:path s:message

> /error s:path i:error_code s:message

:::: Quit

  There is no message for this. Clients will receive the Unix SIGTERM
  signal and *MUST* close cleanly *IMMEDIATELY*, without displaying
  any kind of dialog to the user and regardless of whether or not
  unsaved changes would be lost. When a session is closed the
  application will receive this signal soon after having responded to
  a `save` message.

:::: Open 

> /nsm/client/open s:path_to_instance_specific_project s:display_name s:client_id

  `path\_to\_instance\_specific\_project` is a path name assigned to
  the client for storing its project data.

  The client may append to the path, creating a sub-directory,
  e.g. '\/song.foo' or simply append the client's native file extension
  (e.g. '.non' or '.XML'). The same transformation *MUST* be applied
  to the name when opening an existing project, as NSM will only
  provide the instance specific part of the path.

  If a project exists at the path, the client *MUST* immediately open
  it.

  If a project does not exist at the path, then the client *MUST*
  immediately create and open a new one at the specified path or, for
  clients which hold all their state in memory, store the path for
  later use when responding to the `save` message.

  No file or directory will be created at the specified path by the
  server. It is up to the client to create what it needs.

  For clients which *HAVE NOT* specified the `:switch:` capability,
  the `open` message will only be delivered once, immediately
  following the `announce` response.

  For clients which *HAVE* specified the `:switch:` capability, the
  client *MUST* immediately switch to the specified project or create
  a new one if it doesn't exist.

  Clients which are incapable of switching projects or are prone to
  crashing upon switching *MUST NOT* include `:switch:` in their
  capability string.

  If the user the is allowed to run two or more instances of the
  application simultaneously (that is to say, there is no technical
  limitation preventing them from doing so, even if it doesn't make
  sense to the author), then such an application *MUST PRE-PEND* the
  provided `client\_id` string to any names it registers with common
  subsystems (e.g. JACK client names). This ensures that multiple
  instances of the same application can be restored in any order
  without scrambling the JACK connections or causing other
  conflicts. The provided `client\_id` will be a concatenation of the
  value of `application\_name` sent by the client in its `announce`
  message and a unique identifier. Therefore, applications which
  create single JACK clients can use the value of `client\_id` directly
  as their JACK client name. Applications which register multiple JACK
  clients (e.g. Non-Mixer) *MUST PRE-PEND* `client\_id` value to the
  client names they register with JACK and the application determined
  part *MUST* be unique for that (JACK) client.

  For example, a suitable JACK client name would be:

> $CLIENT_ID/track-1

  Note that this means that the application *MUST NOT* register with
  JACK (or any other subsystem requiring unique names) until it
  receives an `open` message from NSM. Likewise, applications with the
  `:switch:` capability should close their JACK clients and re-create
  them with using the new `client\_id`. Re-registering is necessary
  because the JACK API does currently support renaming existing
  clients, although this is a sorely needed addition.

  A response is *REQUIRED* as soon as the open operation has been
  completed.  Ongoing progress may be indicated by sending messages to
  `\/nsm\/client\/progress`.

::::: Response

  The client *MUST* respond to the 'open' message with:

> /reply "/nsm/client/open" s:message

  Or

> /error "/nsm/client/open" i:error_code s:message

// Response Codes
[[ Code, Meaning
[[ ERR, General Error
[[ ERR_BAD_PROJECT, An existing project file was found to be corrupt
[[ ERR_CREATE_FAILED, A new project could not be created
[[ ERR_UNSAVED_CHANGES, Unsaved changes would be lost
[[ ERR_NOT_NOW, Operation cannot be completed at this time

:::: Save

> /nsm/client/save

  This message will only be delivered after a previous `open` message,
  and may be sent any number of times within the course of a session
  (including zero, if the user aborts the session).

  If able to, the client *MUST* immediately save the current
  application specific project data to the project path previously
  established in the 'open' message. *UNDER NO CIRCUMSTANCES* should a
  dialog be displayed to the user (giving a choice of where to save,
  etc.)
  
  However, if the client is incapable of saving at the specific moment
  without disturbing the user (e.g. a JACK client that can't save
  while the transport is rolling without causing massive XRUNS), then
  the client may respond to "/error" with ERR_NOT_NOW and a string
  explaining exactly why the save could not be completed (so that, in
  this example, the user knows that they have to stop the transport in
  order to save).

::::: Response

  The client *MUST* respond to the 'save' message with:

> /reply "/nsm/client/save" s:message

  Or

> /error "/nsm/client/save" i:error_code s:message

// Response Codes
[[ Code, Meaning
[[ ERR, General Error
[[ ERR_SAVE_FAILED, Project could not be saved
[[ ERR_NOT_NOW, Operation cannot be completed at this time

::: Server to Client Informational Messages

:::: Session is Loaded
 
  Accepting this message is optional. The intent is to signal to
  clients which may have some interdependence (say, peer to peer OSC
  connections) that the session is fully loaded and all their peers
  are available. Most clients will not need to act on this
  message. This message has no meaning when a session is being built
  or run--only when it is initially loaded. Clients who intend to act
  on this message *MUST* not do so by delaying initialization waiting
  for it.

> /nsm/client/session_is_loaded

  This message does not require a response.

:::: Show Optional Gui

  If the client has specified the `optional-gui` capability, then it
  may receive this message from the server when the user wishes to
  change the visibility state of the GUI. It doesn't matter if the
  optional GUI is integrated with the program or if it is a separate
  program \(as is the case with SooperLooper\). When the GUI is
  hidden, there should be no window mapped and if the GUI is a
  separate program, it should be killed.

> /nsm/client/show_optional_gui 

> /nsm/client/hide_optional_gui

  No response is message is required.

::: Client to Server Informational Messages

  These are optional messages which a client can send to the NSM
  server to inform it about the client's status. The client should not
  expect any reply to these messages. If a client intends to send a
  message described in this section, then it *MUST* add the
  appropriate value to its `capabilities` string when composing the
  `announce` message.

:::: Optional GUI

  If the client has specified the `optional-gui` capability, then it
  *MUST* send this message whenever the state of visibility of the
  optional GUI has changed. It also *MUST* send this message after
  it's announce message to indicate the initial visibility state of
  the optional GUI.

  It is the responsibility of the client to remember the visibility
  state of its GUI across session loads.

> /nsm/client/gui_is_hidden

> /nsm/client/gui_is_shown

  No response will be delivered.

:::: Progress

> /nsm/client/progress f:progress

  For potentially time-consuming operations, such as `save` and
  `open`, progress updates may be indicated throughout the duration by
  sending a floating point value between 0.0 and 1.0, 1.0 indicating
  completion, to the NSM server.

  The server will not send a response to these messages, but will
  relay the information to the user.

  Note that even when using the `progress` feature, the final
  response to the `save` or `open` message is still *REQUIRED*.

  Clients which intend to send `progress` messages should include
  `:progress:` in their `announce` capability string.

:::: Dirtiness

> /nsm/client/is_dirty

> /nsm/client/is_clean

  Some clients may be able to inform the server when they have unsaved
  changes pending. Such clients may optionally send `is\_dirty` and `is\_clean`
  messages. 

  Clients which have this capability should include `:dirty:` in their
  `announce` capability string.

:::: Status Messages

> /nsm/client/message i:priority s:message

  Clients may send miscellaneous status updates to the server for
  possible display to the user. This may simply be chatter that is
  normally written to the console. `priority` should be a number from
  0 to 3, 3 being the most important.

  Clients which have this capability should include `:message:` in their
  `announce` capability string.

::: Error Code Definitions

// Error Code Definitions
[[ Symbolic Name, Integer Value
[[ ERR_GENERAL,          -1
[[ ERR_INCOMPATIBLE_API, -2
[[ ERR_BLACKLISTED,      -3
[[ ERR_LAUNCH_FAILED,    -4
[[ ERR_NO_SUCH_FILE,     -5
[[ ERR_NO_SESSION_OPEN,  -6
[[ ERR_UNSAVED_CHANGES,  -7
[[ ERR_NOT_NOW,          -8
[[ ERR_BAD_PROJECT,      -9
[[ ERR_CREATE_FAILED,    -10

::: Client to Server Control

  If the server publishes the `:server-control:` capability, then
  clients can also initiate action by the server. For example, a
  client might implement a 'Save All' option which sends a
  `\/nsm\/server\/save` message to the server, rather than requiring
  the user to switch to the session management interface to effect the
  save.

::: Server Control API

  The session manager not only manages clients via OSC, but it is
  itself controlled via OSC messages. The server responds to the
  following messages.

  All of the following messages will be responded to, at the sender's
  address, with one of the two following messages:

> /reply s:path s:message

> /error s:path i:error_code s:message
 
  The first parameter of the reply is the path to the message being
  replied to. The `\/error` reply includes an integer error code
  (non-zero indicates error). `message` will be a description of the
  error.

  The possible errors are:

// Responses
[[ Code, Meaning
[[ ERR_GENERAL, General Error
[[ ERR_LAUNCH_FAILED, Launch failed
[[ ERR_NO_SUCH_FILE, No such file
[[ ERR_NO_SESSION, No session is open
[[ ERR_UNSAVED_CHANGES, Unsaved changes would be lost

= /nsm/server/add s:executable_name

  Adds a client to the current session.

= /nsm/server/save

  Saves the current session.

= /nsm/server/open s:project_name

  Saves the current session and loads a new session.

= /nsm/server/new s:project_name

  Saves the current session and creates a new session.

= /nsm/server/duplicate s:new_project

  Saves and closes the current session, makes a copy, and opens it.

= /nsm/server/close

  Saves and closes the current session.

= /nsm/server/abort

  Closes the current session *WITHOUT SAVING*  

= /nsm/server/quit

  Saves and closes the current session and terminates the server.

= /nsm/server/list 

  Lists available projects. One `\/reply` message will be sent for each existing project.

:::: Client to Client Communication

  If the server includes `:broadcast:` in its capability string, then
  clients may send broadcast messages to each other through the NSM
  server.
  
  Clients may send messages to the server at the path
  `\/nsm\/server\/broadcast`.

  The format of this message is as follows:

> /nsm/server/broadcast s:path [arguments...]

  The message will then be relayed to all clients in the session at
  the path `path` (with the arguments shifted by one). 

  For example the message:

>  /nsm/server/broadcast /tempomap/update "0,120,4/4:12351234,240,4/4"

  Would broadcast the following message to all clients in the session
  (except for the sender), some of which might respond to the message
  by updating their own tempo maps.

>  /tempomap/update "0,120,4/4:12351234,240,4/4"

  The Non programs use this feature to establish peer to peer OSC
  communication by symbolic names (client IDs) without having to
  remember the OSC URLs of peers across sessions.
