Standards:MUD Client Media Protocol

From Mudlet
Jump to navigation Jump to search
This page contains changes which are not marked for translation.

MUD Client Media Protocol (MCMP)

A Standard for Loading, Playing, Placing and Stopping Media Files with MUD Clients over GMCP

At a glance

  • A game server sends GMCP messages in the Client.Media package, and the client plays sound, music and video from files it downloads or that the player has installed.
  • Client.Media.Default and Client.Media.Load get files ready. Client.Media.Play starts them, with optional fades, loops, priorities and captions, and Client.Media.Stop ends them.
  • With version 2, a game can say where a sound comes from. direction or pan on Client.Media.Play places it, Client.Media.Update moves it while it plays, and Client.Media.Listener says which way the player faces.
  • A game sends the same messages to every client. A client reports its version with Core.Supports.Set, and a version 1 client ignores the keys and messages it does not know and plays the sound as before.
  • Please discuss this standard in the MUDstandards channel of the MUD Discord server.

Status of this Memo

This memo describes the Client.Media namespace of the Generic Mud Communication Protocol (GMCP) telnet sub-negotiation protocol (201). It gives the syntax and usage of the JSON messages a game server sends to a text-based game client to load, play, place, move and stop media files. Any client or server can implement them from this memo alone. Mudlet 5.1 and later implement version 2.

Overview and Rationale

With renewed interest in the MUD genre of gaming, expectations are high to provide sight and sound content that competes for audience with other gaming platforms. The MUD Client Media Protocol (MCMP) delivers media, such as game sounds, background music and video snippets, to text-based game clients via their widely accepted messaging platform, GMCP, which uses JSON as its data-interchange format. It aims to improve the MUD gaming experience and accessibility through standardized messaging between game servers and game clients. MCMP is inspired by its predecessor Mud Sound Protocol (MSP).

Version 2 lets a game say where a sound comes from, so a player hears a door creak to the north or footsteps coming up from behind, and a blind player can tell where things are.

The design follows three rules:

  • Everything new falls back. Version 2 adds only optional keys and messages. A client that does not know one ignores it and plays the sound as before, so a game sends one message to every client.
  • Where a sound comes from never depends on hearing it. A client that places a sound also names the direction in the caption it shows.
  • Games use the words they already have. A game says north or behind instead of giving coordinates, and each client renders that as well as it can, in 3D, in stereo, or not at all.

Video Demonstration of Client.Media

Overview of the GMCP (201) Sub-negotiation Protocol

GMCP is a bidirectional telnet sub-negotiation protocol (see RFC 854) which fulfills the following conditions:

  • GMCP is separated into several ‘namespaces’, which may be enabled or disabled by the client at any time. The ‘Core’ namespace is always enabled and may not be disabled. Namespaces should consist of case-insensitive alphabetical characters and stop characters (. - ASCII 46/0x2E), representable as [A-Za-z.].
  • GMCP messages consist of the namespace and a command (case insensitive alpha characters) delineated by a stop character, and optionally a space character and JSON-encoded payload.
  • GMCP messages may be sent by either the client or the server at any time with no warning.

Client.Media is part of the Client.* meta-namespace, and is reserved for game client media operations and future additions to them.

Conventions

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be read as described in RFC 2119.

Term Meaning
Media A sound, music or video file, as its type says.
Placed sound A sound heard from one point, because it was given a direction or a pan.
Facing The way the player faces. North, until a game says otherwise with Client.Media.Listener.
Angle Where a sound is from the player's point of view, in degrees clockwise: 0 is ahead, 90 right, 180 behind and 270 left. A compass direction's angle is its bearing minus the facing.
3D client A client that can place a sound all around the player, including behind, above and below, such as on headphones.
Stereo client A client that can place a sound only between left and right.

Specification for Client.Media

The Client.Media family of GMCP packages lets games play sound, music and video. Its messages go in one direction, from game server to game client. A player may download media files by hand, and a client may download them automatically.

Message Purpose Version
Client.Media.Default Set the default URL to download media files from 1
Client.Media.Load Download a media file ahead of time 1
Client.Media.Play Play media. Its direction and pan keys say where a sound comes from 1, and 2 for those keys
Client.Media.Update Move a sound that is playing, or change the volume of media that is playing 2
Client.Media.Listener Say which way the player faces 2
Client.Media.Pause Pause media until a later Play resumes it 2
Client.Media.Stop Stop media 1

Versions and Compatibility

A client SHOULD advertise that it supports Client.Media, with its version number, in a Core.Supports message to the server. A version 1 client sends Client.Media 1.

Core.Supports.Set ["Client.Media 2", ...]
  • A client SHOULD advertise version 2 only once it renders direction and pan and handles Client.Media.Update, Client.Media.Listener and Client.Media.Pause, since servers rely on it.
  • A server SHOULD look for the package name, Client.Media, and read the number after it. A server that looks for the exact text Client.Media 1 does not recognize a version 2 client.
  • A version 1 client ignores keys and messages it does not know and plays the sound as before, so a server MAY send version 2 keys to every client.
  • A server SHOULD check for version 2 before its gameplay depends on hearing where a sound comes from, such as an audio-only puzzle.
  • Version 2 adds no new values for type, since a client may drop a whole message whose type it does not know, as Mudlet does.

Messages from the Server

Legacy gaming platforms may not support all JSON data types, such as boolean (true and false), so game clients SHOULD also accept booleans and numbers within the Client.Media namespace as strings (surrounded by quotes).

Times are in milliseconds: 1000 milliseconds is 1 second.

Client.Media.Default

Sets the default URL directory to download media files from. A game whose media files download automatically sends this once upon player login.

Client.Media.Default {"url": "https://www.example.com/media/"}
Key Required Value Purpose
url Yes URL Where the media file can be downloaded from. The last character MUST be a / (slash).


Note Note:

Some examples are shown here.

Client.Media.Load

Downloads a media file from an external source ahead of time, for games whose media files download automatically and can be cached by the game client.

Client.Media.Load {
  "name": "sword1.mp3",
  "url": "https://www.example.com/media/"
}
Key Required Value Purpose
name Yes file name Name of the media file. It may contain directory information, such as weather/lightning.mp3.
url Maybe URL Where the media file can be downloaded from. The last character MUST be a / (slash). Required only if no URL was set with Client.Media.Default.


Note Note:

Some examples are shown here.

Client.Media.Play

Plays media files. A client MAY play only one media file at a time, or several.

Client.Media.Play {
  "name": "80_Blacksmith_Shoppe.mp3",
  "url": "https://www.example.com/media/",
  "type": "music",
  "tag": "environment",
  "volume": 25,
  "fadein": 5000,
  "fadeout": 7000,
  "start": 1000,
  "finish": 20000,
  "loops": 3,
  "priority": 60,
  "continue": true,
  "key": "area-background-music",
  "caption": "Blacksmith Hammering"
}
Key Required Value Default Purpose
name Yes file name none Name of the media file. It may contain directory information, such as weather/lightning.mp3.
url Maybe URL none Where the media file can be downloaded from. The last character MUST be a / (slash). Required only if the client has to download the file and no URL was set with Client.Media.Default or Client.Media.Load.
type No "sound", "music" or "video" "sound" The type of media.
tag No text none Helps categorize media.
volume No 1 to 100 50 Relative to the volume set on the player's client.
fadein No milliseconds none Volume rises linearly from one to volume over this many milliseconds from the start of the media.
fadeout No milliseconds none Volume falls linearly from volume to one over this many milliseconds before the end of the media.
start No milliseconds 0 Begin play at this position.
finish No milliseconds the end of the media End play at this position.
loops No -1, or 1 or more 1 How many times the media plays. -1 loops the sound or music indefinitely.
priority No 1 to 100 none Halts current or future media with a lower priority while this media plays.
continue No true or false true true continues playing matching new music files, and false restarts them.
key No text none Uniquely identifies media files with a key that is bound to their name or url. Halts current media with the same key and a different name or url while this media plays.
caption No text none Text for captions, such as onomatopoeia or sound cues (thunderclap, whoosh).
direction (version 2) No a direction word, or degrees from 0 to 359 none, so the sound plays as recorded Where the sound comes from. See Where a Sound Comes From.
pan (version 2) No -100 to 100 none, so the sound plays as recorded Left (-100) to right (100). See Where a Sound Comes From.
stream (optional) No true or false false true plays the media as a stream from url and name, such as internet radio, without downloading the file first.
close (optional) No true or false false Video only. true closes the video's window when the video ends or is stopped.
  • A client MAY support stream and close, and ignores them if it does not. A server SHOULD send stream only to a client it knows supports it. A client that ignores the key tries to download the stream as a file, and that download never ends.
  • A client plays a stream only over HTTP or HTTPS, as with a download, and does not cache it.


Note Note:

A game can use the caption field to give contextual text to players with hearing impairments or who prefer captioned media. For best practices, see DCMP Captioning Key: Sound Effects and Music.

Note Note:

Some examples are shown here.
Where a Sound Comes From

A version 1 client ignores direction and pan and plays the sound as it always has.

direction is for games that think in exits and compass points:

  • Compass words are the ones MUD exits use: north, northeast, east, southeast, south, southwest, west, northwest, up and down, and the short forms n, ne, e, se, s, sw, w, nw, u and d. With no facing, north is ahead and east is to the right, like a map with north at the top. A game whose player has a facing can say so with Client.Media.Listener.
  • Relative words are ahead, behind, left and right. They are always relative to the player and ignore the facing, so ahead has an angle of 0, right 90, behind 180 and left 270. They are for games without compass exits.
  • Degrees run clockwise from north: 0 is north and 90 is east. A client reads a number outside 0 to 359 as the same direction on the circle, so 360 is north.
  • Words are not case sensitive.
  • A word the client does not recognize is ignored, and the sound plays as with no direction, so a game can pass any exit name. For a sound through an exit with no compass direction, such as in or a portal, say where it comes from in caption, such as footsteps from the shop.

pan is for games that think in speakers rather than compass points, or want a fixed placement. It runs from left (-100) to right (100), and a client treats a value outside that range as the nearest end of it. 0 places the sound at the center, heard from one point. With no pan, it plays as recorded.

Each client renders as much as it can:

  • A 3D client places the sound at its angle, including behind, above and below. How high it places up and down is its own choice. Directly overhead and underfoot are hard to hear on headphones, so it may use a smaller angle, such as 45° to 60°.
  • A stereo client turns a direction into pan = 100 × sin(angle). With no facing, east is fully right, west fully left, and north and south are centered. up and down name no side, so a stereo client plays those sounds as with no direction.
  • A client with no panning plays the sound as recorded, as in version 1.

For every client:

  • A placed sound is heard from one point. A stereo recording is mixed to one point first. A sound with neither direction nor pan plays as recorded, stereo image included.
  • Both keys. When a message has both pan and direction, a 3D client uses direction and a stereo client uses pan. That lets a game tune the result for each kind of client.
  • Captions. A client that shows captions SHOULD add the direction to them, such as a door creaks (north), so that where a sound comes from never depends on hearing it.
  • Music and video. These keys are for sounds. A client MAY ignore direction and pan on "music" and "video".
  • pan uses the same -100 to 100 scale as MUSHclient's PlaySound, and the same key as the Mongoose MOO web client's MCMP extension, so a game sending pan is understood by more than one client.

Examples

A door to the north. With no facing, the player hears it ahead, and a client with captions shows a door creaks (north):

Client.Media.Play {
  "name": "door-creak.wav",
  "key": "north-door",
  "volume": 60,
  "direction": "north",
  "caption": "a door creaks"
}

A drip that stays on the player's left, whichever way they face: {"name": "drip.wav", "pan": -60}

A sound tuned for each kind of client, behind the player on a 3D client and a little to the left on a stereo one: {"name": "wolf.wav", "direction": "behind", "pan": -30}

Client.Media.Update

Version 2. Moves a sound that is already playing, or changes the volume of media that is playing, without restarting it. For sounds that travel, such as footsteps coming up from behind or an arrow in flight, send a few updates as the sound moves. A version 1 client ignores this message, so the sound stays where it started.

Client.Media.Update {
  "key": "dragon",
  "direction": "south",
  "volume": 80,
  "duration": 2000
}
Key Required Value Default Purpose
key Maybe text none Selects media with this key. At least one of key, name or tag is required, and media must match all that are given. To move several copies of one sound separately, give each its own key when it is played, such as arrow-1 and arrow-2.
name Maybe file name none Selects media by name, the same way Client.Media.Stop does. Every playing copy of that file changes.
tag Maybe text none Selects media with this tag.
type No "sound", "music" or "video" any Narrows the selection to one type. On its own it selects nothing, as it would otherwise change every sound of that type.
volume No 1 to 100 unchanged The new volume.
direction No as on Client.Media.Play unchanged The new direction.
pan No -100 to 100 unchanged The new pan.
duration No milliseconds 0 How long the change takes, as the sound glides from its old values to the new ones. For a traveling sound, give the time it takes to get there. 0 makes the change at once, and a client MAY take up to 20 milliseconds over it, so that the jump does not click.
  • Straight after a Play. An update may follow its Play at once, before the file has loaded or downloaded. It applies once the sound plays.
  • A new direction replaces an earlier pan. An update with direction and no pan clears any pan the sound had, or a stereo client would never move it. An update with only pan leaves the direction as it was.
  • Captions. A client does not caption an update. The Play was captioned, and an update only changes how that sound is heard.

Example: A cart that crosses from west to east in four seconds

Client.Media.Play {"name": "cart.wav", "key": "cart", "direction": "west", "caption": "a cart rolls past"}
Client.Media.Update {"key": "cart", "direction": "east", "duration": 4000}


Note Note:

Some examples are shown here.

Client.Media.Listener

Version 2. Tells the client which way the player faces, so that compass directions are heard relative to it. Most games never send it. Ships, vehicles and games that say "to your left" would. A version 1 client ignores it.

Client.Media.Listener {"facing": "east"}
Key Required Value Default Purpose
facing Yes a compass word other than up or down, or degrees from 0 to 359 "north" Turns the compass. Facing "east", a sound from the east is ahead and one from the north is to the left.
  • Relative words are unaffected, as they are always relative to the player.
  • A facing the player cannot turn to, such as up or a relative word, is ignored, and the player keeps the facing they had.
  • Sounds that are playing turn with the facing, except those with a pan, which is a fixed placement.
  • A facing lasts for the connection. After a reconnect the client faces north again, or the player's own choice where the client offers one, until the game sends Client.Media.Listener again.


Note Note:

Some examples are shown here.

Client.Media.Pause

Version 2. Pauses media that is playing, and a later Play resumes it from the same place. An empty body pauses all media. A version 1 client ignores it, and the media keeps playing.

Client.Media.Pause {
  "name": "city.mp3",
  "type": "music",
  "tag": "environment",
  "priority": 60,
  "key": "area-background-music"
}
Key Required Value Purpose
name No file name Pauses media by name matching the value specified.
type No "sound", "music" or "video" Pauses media by type matching the value specified.
tag No text Pauses media by tag matching the value specified.
priority No 1 to 100 Pauses media with a priority lower than the value.
key No text Pauses media by key matching the value specified.
  • Resuming. A Client.Media.Play that matches paused media resumes it where it paused rather than starting it again. A Play with a key or tag and no name resumes the paused media it matches.
  • Stopping. Client.Media.Stop stops paused media too.

Example: Music that pauses while the player reads a scroll

Client.Media.Pause {"key": "area-background-music"}
Client.Media.Play {"key": "area-background-music"}


Note Note:

Some examples are shown here.

Client.Media.Stop

Stops playing media files. An empty body stops all media.

Client.Media.Stop {
  "name": "city.mp3",
  "type": "music",
  "tag": "environment",
  "priority": 60,
  "key": "area-background-music",
  "fadeaway": true,
  "fadeout": 7000
}
Key Required Value Purpose
name No file name Stops playing media by name matching the value specified.
type No "sound", "music" or "video" Stops playing media by type matching the value specified.
tag No text Stops playing media by tag matching the value specified.
priority No 1 to 100 Stops playing media with priority less than or equal to the value.
key No text Stops playing media by key matching the value specified.
fadeaway No true or false Decreases volume from the current position for a given duration, then stops the media. That duration is the lesser of the media's remaining duration and the fadeout specified in Client.Media.Play. If Client.Media.Play gave no fadeout, then the fadeout key of this message or a default of 5000 milliseconds applies.
fadeout No milliseconds Default duration to decrease volume to the end of the media. Only used if fadeout was not defined in Client.Media.Play.


Note Note:

Some examples are shown here.

Security

A media message comes from the game server, and a client acts on its file names and URLs. Clients MUST treat them as untrusted input:

  • Keep files in the media folder. Refuse a name that is an absolute path, or that leads out of the folder through .. or a symbolic link. A client writes what it downloads under these names, so a game could otherwise overwrite the player's files, or read them.
  • Fetch only over HTTP or HTTPS. Refuse any other scheme, such as file:, so that a URL cannot turn a download into reading a local file.

Guidance for Servers

Add features in steps:

  1. Sound and music. Send Client.Media.Default once upon player login, then Client.Media.Play and Client.Media.Stop.
  2. Captions. Give each sound a caption, for players with hearing impairments or who prefer captioned media.
  3. Direction. Add direction to sounds that come from somewhere. You can send it to any client, and need to check for version 2 only if gameplay depends on it.
  4. Movement. Give a traveling sound a key, and send Client.Media.Update as it moves.
  5. Facing. If the player has a facing, such as on a ship, send Client.Media.Listener when it changes and again after each reconnect.

Also follow these practices from web applications and browsers:

  • Avoid autoplay before the player has interacted. Media files should not play immediately upon client connection, especially before the player has had a chance to interact with the game. Some clients, particularly web-based ones, may block or suppress autoplay, and it can disrupt players.
  • Use secure media URLs. Whenever possible, serve media files over HTTPS. HTTP links may trigger mixed content warnings or blocked requests in web-based clients and in operating systems with strict security policies.

Consider advertising your game's support of MCMP (and GMCP) to MUD lists via the Mud Server Status Protocol, MSSP, by providing an MSSP variable of "MCMP" and a value of "1". A game that sends version 2 messages gives the value "2".

Guidance for Clients

Implement in levels, and follow the security rules from the start:

  1. Support Client.Media.Default, Client.Media.Load, Client.Media.Play and Client.Media.Stop, with captions, and advertise Client.Media 1.
  2. Support direction and pan on sounds in stereo, and name the direction in captions.
  3. Support Client.Media.Update, Client.Media.Listener and Client.Media.Pause, then advertise Client.Media 2.
  4. If the platform allows it, place sounds in 3D, perhaps behind a preference for speakers or headphones.

Notes for Web Client Developers

Browser security models limit media playback in ways neither the game server nor the client developer controls:

  • Most browsers restrict media autoplay until the user has interacted with the page, so a Client.Media.Play sent immediately after connection may not play.
  • Serving media over non-HTTPS URLs may result in blocked requests or mixed content warnings, depending on the browser and hosting setup.
  • A browser can pan media from another site only when that site sends CORS headers; otherwise the panned sound comes out silent. This is one reason clients may ignore pan and direction on music, which is often streamed from elsewhere.

Where possible, client developers may want to inform players or log these situations for debugging.

Quick Reference

Every message, with every key:

Client.Media.Default {"url": "https://www.example.com/media/"}

Client.Media.Load {"name": "sword1.mp3", "url": "https://www.example.com/media/"}

Client.Media.Play {
  "name": "door-creak.wav", "url": "https://www.example.com/media/",
  "type": "sound", "tag": "environment", "volume": 50,
  "fadein": 500, "fadeout": 500, "start": 0, "finish": 3000,
  "loops": 1, "priority": 50, "continue": true,
  "key": "north-door", "caption": "a door creaks",
  "direction": "north", "pan": 0, "stream": false, "close": false
}

Client.Media.Update {
  "key": "north-door", "name": "door-creak.wav", "tag": "environment", "type": "sound",
  "volume": 80, "direction": "south", "pan": 0, "duration": 2000
}

Client.Media.Listener {"facing": "east"}

Client.Media.Pause {
  "name": "door-creak.wav", "type": "sound", "tag": "environment", "priority": 50,
  "key": "north-door"
}

Client.Media.Stop {
  "name": "door-creak.wav", "type": "sound", "tag": "environment", "priority": 50,
  "key": "north-door", "fadeaway": true, "fadeout": 500
}

Left Out on Purpose

These came up in the discussion of version 2, and were left out to keep the protocol small:

  • distance: volume stays the one control of loudness, so a sound is never made quieter twice.
  • Separate ids for each playing sound: A key already names one sound, so each copy that should move on its own is given its own key.
  • Attaching a position to a later Play: A game can add direction to the Play it sends.
  • Height in degrees: up and down are how MUDs describe height.
  • A separate package wrapping Client.Media.Play: A version 1 client ignores the new keys, so a game sends one message to every client.
  • Coordinates, rooms and reverb: These need an agreed frame of reference (which axis is north, which way is up, and what the units are), and clients that already use coordinates disagree on it. They could be a later version.

Versions

  • Version 1.0: Initial specification.
  • Version 1.0.1: fadein, fadeout and start added to Client.Media.Play by Mike Conley (mike.conley[at]stickmud.com) on 22-DEC-2021.
  • Version 1.0.2: finish added to Client.Media.Play and fadeaway and fadeout added to Client.Media.Stop by Mike Conley (mike.conley[at]stickmud.com) on 10-DEC-2023.
  • Version 1.0.3: caption added to Client.Media.Play for improved accessibility by Mike Conley (mike.conley[at]stickmud.com) on 10-MAY-2025.
  • Version 2: direction and pan added to Client.Media.Play; Client.Media.Update, Client.Media.Listener and Client.Media.Pause added; stream and close listed as optional keys of Client.Media.Play; "Client.Media 2" advertised in Core.Supports. By Mike Conley (mike.conley[at]stickmud.com), with feedback from SlySven, w, Sammer (Luke) and vadi2 in the MUDstandards channel and in review. First implemented in Mudlet 5.1, released on 01-NOV-2026.

Authors

  • Mike Conley (Tamarindo, Co-Administrator at StickMUD and Mudlet contributor) mike.conley[at]stickmud.com
  • Eric Oestrich (Developer of ExVenture and Grapevine) eric[at]oestrich.org

Clients

  • Known clients implementing this specification:
    • Mudlet 4.4 and later, and version 2 from Mudlet 5.1. See documentation.
    • BeipMU version 4.00.298 implements basic load/play/stop commands.
    • LociTerm version 2.5.1 and beyond.

References