OCP Pipeline¶
Maturity — Stable ⬤⬤⬤⬤◯
Established and production-ready, actively maintained. Rated by repository health, not version.
In a nutshell
When you say "play some jazz" or "next song", the assistant first has to realise you are talking about media and not, say, the weather. This is the part that does that: it spots that an utterance is a playback request, figures out what kind of media you want, asks the installed music/podcast/video skills to search for it, and hands the best result off to be played. Think of it as the dispatcher that turns "play X" into actual playback. See the Intent Pipeline overview or the Glossary for related terms.
What OCP means here
"OCP" names three different things in OVOS. Know which one a page is about:
- The OCP pipeline plugin: matches utterances like "play some jazz" to a media request. See OCP Pipeline.
- The OCP skill base class:
OVOSCommonPlaybackSkill; skills built on it provide or embody media for the pipeline to find. See OCP Skills. - The legacy OCP audio plugin:
ovos-plugin-common-play, the current default playback engine running insideovos-audio. See The OCP Audio Plugin.
Shipped in the default pipeline.
The rest of this page is for people deploying or customizing OVOS. If you only wanted to know what this stage does, you are done.
📐 Formal specification
The media player this pipeline drives is specified by OVOS-OCP-1 — OVOS Common Playback: the per-session Virtual Media Player and its ovos.common_play.* control surface. The matching/classification side is a pipeline plugin under OVOS-PIPELINE-1 (OCP-1 explicitly leaves the NLU to PIPELINE-1). Media stop is one subscriber to the OVOS-STOP-1 cascade. See the spec index.
The OCP (OVOS Common Play) Pipeline Plugin handles media playback commands:
"play some jazz", "pause", "next song". It recognises that an utterance is about
media, works out what kind of media is wanted, asks OCP-enabled skills to search
for it, filters the results, and hands the best one to the active player to play.
That player is ovos-audio's legacy OCP backend by default, or the ovos-media daemon if enabled.
Skills act purely as catalogs: they return search results, they do not play anything themselves. OCP centralises selection and playback.
Quick start¶
It exposes confidence-tiered matchers (ovos-ocp-pipeline-plugin-high,
ovos-ocp-pipeline-plugin-medium, ovos-ocp-pipeline-plugin-low) plus a legacy
matcher (ovos-ocp-pipeline-plugin-legacy). A typical pipeline puts the high tier
early and the low tier last:
{
"intents": {
"pipeline": [
"ovos-ocp-pipeline-plugin-high",
"ovos-padatious-pipeline-plugin-high",
"ovos-adapt-pipeline-plugin-high",
"ovos-ocp-pipeline-plugin-medium",
"ovos-fallback-pipeline-plugin-medium",
"ovos-ocp-pipeline-plugin-low"
]
}
}
The older short names ocp_high / ocp_medium / ocp_low / ocp_legacy still work
as deprecated aliases (ovos-core rewrites them to the canonical IDs above), but new
configs should use the canonical names.
Then install OCP-enabled media skills and ask to play something.
Pipeline matchers¶
The matcher class is OCPPipelineMatcher, registered under the single OPM entry point
ovos-ocp-pipeline-plugin. Because it is a ConfidenceMatcherPipeline, OVOS derives three
tier matchers from it at runtime via match_high / match_medium / match_low — you reference
them in the pipeline by the IDs below (the short ocp_* aliases are deprecated):
| Pipeline ID | Legacy alias | Tier | When to use |
|---|---|---|---|
ovos-ocp-pipeline-plugin-high |
ocp_high |
high | Explicit OCP intents ("play.intent", "pause", "next") — primary media commands. |
ovos-ocp-pipeline-plugin-medium |
ocp_medium |
medium | Utterance classified as a media query by keyword matching. |
ovos-ocp-pipeline-plugin-low |
ocp_low |
low | Broad keyword hits — only on devices used mainly for media playback. |
A separate class, MycroftCPSLegacyPipeline, is registered as its own entry point
ovos-ocp-pipeline-plugin-legacy (alias ocp_legacy). It
bridges to deprecated Mycroft CommonPlaySkill (CPS) skills and is off by default.
It is only useful if you still run legacy CPS skills.
ocp_lowkeys off skill-registered media keywords, so it can fire on phrases that merely contain a known artist or show name even when no playback was intended. Place it last and only enable it on media-focused devices.
Playback vs. control, and why ordering matters
OCP-1 §2 splits media commands into two classes the player must distinguish: playback requests ("play X", "open X") that acquire new media, and control requests ("pause", "resume", "next", "previous", "stop", seek) that act on whatever is already playing. This includes media OVOS did not start, when the MPRIS bridge (OCP-1 §6) is enabled. There is exactly one Virtual Media Player per session (OCP-1 §2, §5). A request names the player, not a backend, and the player routes.
This is why a high-tier OCP stage belongs early in session.pipeline: as a selective pipeline plugin it claims a control utterance like "resume" or "next" only while it holds paused media for that session. First-match-wins (PIPELINE-1 §6.2) lets it intercept those bare words before a general intent engine does. This is exactly the conservative, state-aware claiming pattern the spec describes.
Seek on the wire (ovos.common_play.seek) carries a relative seconds delta. The player, not the pipeline matcher, converts it to milliseconds and adds it to its own live playback position, so the result never depends on stale matcher-side state (a separate GUI-only seekValue field carries an absolute position). The ovos.common_play.* bus surface in the spec is the formal counterpart of the ovos.common_play.query / …status / …track.state topics used below.
flowchart TD
U[Utterance] --> Q{"Playback or control?"}
Q -- "play X / open X" --> NEW["Acquire new media\novos.common_play.query"]
Q -- "pause/resume/next/\nprevious/stop/seek" --> CTRL{"Player holding\npaused media?"}
CTRL -- yes --> ACT["Claim as control request"]
CTRL -- no --> PASS["Pass to next pipeline stage"]
Diagram: an utterance is classified as either a playback request, which acquires new media via a common_play query, or a control word, which OCP claims only if it is already holding paused media, otherwise passing it to the next pipeline stage.
How a media intent is recognized¶
OCP combines several signals:
- Explicit intents (
ocp_high): localized.intentfiles for play, pause, resume, stop, next, previous, shuffle, etc. - Keyword matching (
ocp_medium/ocp_low):classify_media()delegates to aContextAwareClassifierbacked by theovos-media-classifierpackage (a hard dependency), which feeds player status and registered NER entities into the classification. The classifier backend is pluggable — the default is a keyword/vocab matcher, but otheropm.media.classifierentry points can be selected via config.is_ocp_query()treats any non-GENERIC media type as a playback query. - Skill-registered keywords: skills announce entities (artist names, show
titles) over
ovos.common_play.register_keyword. These feed theAhocorasickNERentity matcher and bias media-type classification.
If a query maps to exactly one media type that a skill can serve, that type is used with full confidence.
MediaProvider plugins¶
In-process MediaProvider plugins (entry-point group opm.media.provider) run
alongside the legacy bus @ocp_search window rather than replacing it —
results from both are merged, bounded by the same timeout. A provider that
declares no media types is demoted (confidence capped at 50); each provider's
results are capped at 50. With no MediaProvider plugins installed, behavior
is unchanged from the legacy bus-only flow. Settings live under
intents.ovos-ocp-pipeline-plugin.media_providers in mycroft.conf; set
media_providers.enabled: false to turn the mechanism off entirely.
Supported media types include music, podcast, movie, radio, audiobook,
news, and many more from ovos_utils.ocp.MediaType.
Search and result filtering¶
After classifying, OCP emits ovos.common_play.query and gathers
ovos.common_play.query.response results from skills, then filters them in
filter_results():
- Confidence: drops results whose
match_confidenceis belowmin_score. - Media-type consistency: when a non-GENERIC type was classified, results of
other types are removed (
filter_media). - Stream-extractor availability: results needing a Stream Extractor plugin
(SEI) that is not installed are removed (
filter_SEI). Available extractors come from theopm.ocp.extractorplugin group, queried viaovos.common_play.SEI.get. - Playback mode: audio-only / video-only preferences drop incompatible
results (
playback_mode).
OCP tracks player state per Session over the bus (ovos.common_play.status,
ovos.common_play.track.state), so context-dependent commands behave correctly.
For example, "next song" does nothing when no player is active.
Configuration¶
{
"intents": {
"ovos-ocp-pipeline-plugin": {
"legacy": false,
"min_score": 50,
"filter_media": true,
"filter_SEI": true,
"playback_mode": 0,
"search_fallback": true,
"entity_csvs": []
}
}
}
| Key | Type | Default | Description |
|---|---|---|---|
legacy |
bool | false |
Use the classic (Mycroft) audio service API instead of OCP. Not recommended. |
min_score |
int | 50 |
Minimum match_confidence to keep a skill result (0–100). |
filter_media |
bool | true |
Drop results whose media type differs from the classified one. |
filter_SEI |
bool | true |
Drop results needing an unavailable Stream Extractor plugin. |
playback_mode |
int | 0 |
0 = auto, 10 = audio-only, 20 = video-only (PlaybackMode). |
search_fallback |
bool | true |
Run a generic search when no type-specific results are found. |
entity_csvs |
list | [] |
User-supplied keyword CSVs feeding the entity matcher. |
legacy_cps |
bool | true |
Only read by the ovos-ocp-pipeline-plugin-legacy matcher: set false to disable the legacy Mycroft CommonPlay stage entirely. |
The config block is read from intents.ovos-ocp-pipeline-plugin, the plugin's entry-point ID.
Key your config by the plugin ID, not OCP
The plugin-ID key wins: the plugin resolves its config as
intents["ovos-ocp-pipeline-plugin"] or intents["OCP"], so anything you set under
intents.OCP is shadowed the moment the plugin-ID key exists — and the bundled
mycroft.conf always ships that key (including min_score: 40), so in practice
intents.OCP entries change nothing on a stock install. intents.OCP survives only
as a back-compat fallback for configs that define nothing under the plugin ID. Put
yours under the plugin ID:
Gotcha: legacy vs. OCP playback¶
ocp_legacy and legacy: true are two different things. ocp_legacy is a
pipeline matcher that routes to deprecated Mycroft CPS skills. legacy: true forces
OCP to drive playback through the classic audio service API instead of OCP itself.
Leave both off unless you specifically need to support pre-OCP skills.
Source code: OpenVoiceOS/ovos-ocp-pipeline-plugin.
Read next: Common Query Pipeline Related: Media Skills (OCP) · ovos-media OCP Pipeline Plugin · OCP Audio Plugin · Stop Pipeline