Audio detach

Current SoT. Media L2 demux (sume/audio-detach-1.0, #5953). Dest and prod. This is not clip inspection — that is video inspect. For many ranges, detach once then split with timeline audio.

Audio detach 1.0 takes one workspace media.sume.com video and returns a new audio artifact. Default is sample-exact wav (pcm_s16le) — what timeline_create audio.url, POST /v1/timeline-1.0/audio, and speech-to-text want. The video is untouched. The server compiles ffmpeg on the worker media runtime (apps/api/src/routes.ts createAudioDetachV1 / submitSumeAudioDetachJob).

There is no GET /v1/audio-detach/:id. Poll the job envelope:

Hosted MCP: audio_detach (packages/mcp-server/src/mcp.ts). Writes need idempotency_key (and mcp:write under OAuth). Flow: audio_detachjobs_waitjobs_result.

Create a detach

Required: video_url (this workspace’s media.sume.com artifact or asset). There is no open-internet fetch — import first (POST /v1/media-imports). Idempotency-Key is required.

Optional: format, range, channels, sample_rate, plus the usual mode / webhook_url / wait_timeout_seconds communication fields.

Default mode is async. Pass mode: "sync" to wait up to 30 seconds for a 200 finished job, or get 202 and poll.

A successful submit returns a job (request_id is the job id). When result_ready, GET /v1/jobs/:id/result is kind: audio_detach with audio_url (new artf_), duration_seconds, format, channels, sample_rate (null when omitted — inherited from the source), source_duration_seconds, and optional range / warnings[].

Public rate: $0.01 per job (AUDIO_DETACH_PUBLIC_PRICING; confirm live in GET /v1/catalog). No provider inference — worker ffmpeg only.

Program

FieldEffect
formatwav (default, pcm_s16le sample-exact) or mp3 (128 kbps).
rangeOptional { start, end? } seconds. Omit for the whole track. end open-ended when omitted.
channelssource (default) or mono.
sample_rate16000 | 44100 | 48000. Omit to inherit the source. 16000 + channels: "mono" is the STT shape.

Caps (from packages/api-contract/src/index.ts): source ≤ 1800 s; output ≤ 900 s. A whole track past 900 s needs a range.

A source with no audio track fails detach_source_has_no_audio. Check probe.has_audio first with video inspect (frames: false is enough).

Refusals (stable codes)

CodeWhen
audio_detach_range_emptyrange.endrange.start, or the range is longer than 900 s.
detach_source_has_no_audioSource has no audio track (worker).
detach_start_past_sourcerange.start is past the probed duration (worker).
ffmpeg_fields_rejectedClient sent af / filter / ffmpeg / cmd / codec / friends. The server compiles ffmpeg.
unsupported_media_sourcevideo_url is not on the Sume media host.
source_not_foundDead or foreign media.sume.com URL.
unsupported_media_typeHEAD is not a video.
source_duration_exceededSource longer than 1800 s (worker).

Off-host URLs (https://example.com/…) are rejected at admit. Import first.

Not this surface

NeedUse
Probe / stills / optional STTVideo inspect
Exact frame at t, source sizeVideo frames
A new MP4 cutVideo trim
Pixel pass (dim / crop)Video filter
Many audio ranges from one trackDetach once, then timeline audio operation: "split"
Sequence several clipsTimeline 1.0