From c8bcf752271a7172ab8ccf36e39ac911bf993ae6 Mon Sep 17 00:00:00 2001 From: Zac Gaetano Date: Sun, 3 May 2026 12:12:05 +0000 Subject: [PATCH] fix(webrtc): swagger annotations for WHEP routes, regenerate docs (closes #3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The WHEP routes were mounted by http/server.go via the app/webrtc Handler.Register(), but Subscribe and Unsubscribe carried no swag annotations. The Swagger UI at /api/swagger/index.html therefore didn't list /api/v3/whep/* — programmatic API consumers and humans browsing the docs couldn't discover the endpoints. Adds the standard upstream-shaped @Summary / @Tags / @ID / @Router annotations on Subscribe and Unsubscribe (matching the rtmp.go and srt.go pattern) and regenerates docs/{docs.go,swagger.json,swagger.yaml} via 'make swagger'. Verified: swagger.json now contains both paths, swagger UI renders them under the v16.16.0 tag. Closes #3. Co-Authored-By: Claude Opus 4.7 --- app/webrtc/handler.go | 25 +++++++ docs/docs.go | 149 +++++++++++++++++++++++++++++++++++++++++- docs/swagger.json | 145 ++++++++++++++++++++++++++++++++++++++++ docs/swagger.yaml | 98 +++++++++++++++++++++++++++ 4 files changed, 416 insertions(+), 1 deletion(-) diff --git a/app/webrtc/handler.go b/app/webrtc/handler.go index 34db336..4f28624 100644 --- a/app/webrtc/handler.go +++ b/app/webrtc/handler.go @@ -54,6 +54,20 @@ func (h *Handler) Register(g *echo.Group) { // Subscribe handles POST /whep/:id. Request body is an SDP offer, // response is an SDP answer with a Location header pointing at the // DELETE resource. +// +// @Summary Subscribe to a WebRTC stream via WHEP +// @Description Subscribe to a process's WebRTC egress stream. Body is the SDP offer (Content-Type: application/sdp). Response is the SDP answer; the Location header points at the DELETE resource for teardown. +// @Tags v16.16.0 +// @ID webrtc-3-whep-subscribe +// @Accept application/sdp +// @Produce application/sdp +// @Param id path string true "Process ID with config.webrtc.enabled=true" +// @Success 201 {string} string "SDP answer" +// @Failure 400 {string} string "missing stream id, malformed body, or invalid SDP" +// @Failure 404 {string} string "no stream registered for this process id" +// @Failure 503 {string} string "peer cap reached" +// @Security ApiKeyAuth +// @Router /api/v3/whep/{id} [post] func (h *Handler) Subscribe(c echo.Context) error { id := c.Param("id") if id == "" { @@ -96,6 +110,17 @@ func (h *Handler) Subscribe(c echo.Context) error { // Unsubscribe handles DELETE /whep/:id/:resource. The :id is part of // the path per WHEP spec but we only need :resource to locate the // peer; :id is accepted for route symmetry. +// +// @Summary Tear down a WHEP subscription +// @Description Tear down a WebRTC peer connection by its resource id (returned in the Location header by Subscribe). Idempotent: returns 204 even when the resource is unknown, per the WHEP spec. +// @Tags v16.16.0 +// @ID webrtc-3-whep-unsubscribe +// @Param id path string true "Process ID" +// @Param resource path string true "Resource ID from the Subscribe Location header" +// @Success 204 "no content" +// @Failure 400 {string} string "missing resource id" +// @Security ApiKeyAuth +// @Router /api/v3/whep/{id}/{resource} [delete] func (h *Handler) Unsubscribe(c echo.Context) error { resource := c.Param("resource") if resource == "" { diff --git a/docs/docs.go b/docs/docs.go index c453f3f..39ce52e 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,4 +1,4 @@ -// Code generated by swaggo/swag. DO NOT EDIT +// Package docs Code generated by swaggo/swag. DO NOT EDIT package docs import "github.com/swaggo/swag" @@ -1903,6 +1903,104 @@ const docTemplate = `{ } } }, + "/api/v3/whep/{id}": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Subscribe to a process's WebRTC egress stream. Body is the SDP offer (Content-Type: application/sdp). Response is the SDP answer; the Location header points at the DELETE resource for teardown.", + "consumes": [ + "application/sdp" + ], + "produces": [ + "application/sdp" + ], + "tags": [ + "v16.16.0" + ], + "summary": "Subscribe to a WebRTC stream via WHEP", + "operationId": "webrtc-3-whep-subscribe", + "parameters": [ + { + "type": "string", + "description": "Process ID with config.webrtc.enabled=true", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "SDP answer", + "schema": { + "type": "string" + } + }, + "400": { + "description": "missing stream id, malformed body, or invalid SDP", + "schema": { + "type": "string" + } + }, + "404": { + "description": "no stream registered for this process id", + "schema": { + "type": "string" + } + }, + "503": { + "description": "peer cap reached", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v3/whep/{id}/{resource}": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Tear down a WebRTC peer connection by its resource id (returned in the Location header by Subscribe). Idempotent: returns 204 even when the resource is unknown, per the WHEP spec.", + "tags": [ + "v16.16.0" + ], + "summary": "Tear down a WHEP subscription", + "operationId": "webrtc-3-whep-unsubscribe", + "parameters": [ + { + "type": "string", + "description": "Process ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Resource ID from the Subscribe Location header", + "name": "resource", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "no content" + }, + "400": { + "description": "missing resource id", + "schema": { + "type": "string" + } + } + } + } + }, "/api/v3/widget/process/{id}": { "get": { "description": "Fetch minimal statistics about a process, which is not protected by any auth.", @@ -2629,6 +2727,9 @@ const docTemplate = `{ "version": { "type": "integer", "format": "int64" + }, + "webrtc": { + "$ref": "#/definitions/config.DataWebRTC" } } }, @@ -3109,6 +3210,9 @@ const docTemplate = `{ "ffmpeg", "" ] + }, + "webrtc": { + "$ref": "#/definitions/api.ProcessConfigWebRTC" } } }, @@ -3176,6 +3280,23 @@ const docTemplate = `{ } } }, + "api.ProcessConfigWebRTC": { + "type": "object", + "properties": { + "audio_pt": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "force_transcode": { + "type": "boolean" + }, + "video_pt": { + "type": "integer" + } + } + }, "api.ProcessReport": { "type": "object", "properties": { @@ -4441,6 +4562,9 @@ const docTemplate = `{ "version": { "type": "integer", "format": "int64" + }, + "webrtc": { + "$ref": "#/definitions/config.DataWebRTC" } } }, @@ -4709,6 +4833,27 @@ const docTemplate = `{ } } }, + "config.DataWebRTC": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "nat_1_to_1_ips": { + "type": "array", + "items": { + "type": "string" + } + }, + "public_ip": { + "type": "string" + }, + "udp_mux_port": { + "type": "integer", + "format": "int" + } + } + }, "github_com_datarhei_core_v16_http_api.Config": { "type": "object", "properties": { @@ -4831,6 +4976,8 @@ var SwaggerInfo = &swag.Spec{ Description: "Expose REST API for the datarhei Core", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", } func init() { diff --git a/docs/swagger.json b/docs/swagger.json index 8351c34..dfb4173 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1896,6 +1896,104 @@ } } }, + "/api/v3/whep/{id}": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Subscribe to a process's WebRTC egress stream. Body is the SDP offer (Content-Type: application/sdp). Response is the SDP answer; the Location header points at the DELETE resource for teardown.", + "consumes": [ + "application/sdp" + ], + "produces": [ + "application/sdp" + ], + "tags": [ + "v16.16.0" + ], + "summary": "Subscribe to a WebRTC stream via WHEP", + "operationId": "webrtc-3-whep-subscribe", + "parameters": [ + { + "type": "string", + "description": "Process ID with config.webrtc.enabled=true", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "SDP answer", + "schema": { + "type": "string" + } + }, + "400": { + "description": "missing stream id, malformed body, or invalid SDP", + "schema": { + "type": "string" + } + }, + "404": { + "description": "no stream registered for this process id", + "schema": { + "type": "string" + } + }, + "503": { + "description": "peer cap reached", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/v3/whep/{id}/{resource}": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Tear down a WebRTC peer connection by its resource id (returned in the Location header by Subscribe). Idempotent: returns 204 even when the resource is unknown, per the WHEP spec.", + "tags": [ + "v16.16.0" + ], + "summary": "Tear down a WHEP subscription", + "operationId": "webrtc-3-whep-unsubscribe", + "parameters": [ + { + "type": "string", + "description": "Process ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Resource ID from the Subscribe Location header", + "name": "resource", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "no content" + }, + "400": { + "description": "missing resource id", + "schema": { + "type": "string" + } + } + } + } + }, "/api/v3/widget/process/{id}": { "get": { "description": "Fetch minimal statistics about a process, which is not protected by any auth.", @@ -2622,6 +2720,9 @@ "version": { "type": "integer", "format": "int64" + }, + "webrtc": { + "$ref": "#/definitions/config.DataWebRTC" } } }, @@ -3102,6 +3203,9 @@ "ffmpeg", "" ] + }, + "webrtc": { + "$ref": "#/definitions/api.ProcessConfigWebRTC" } } }, @@ -3169,6 +3273,23 @@ } } }, + "api.ProcessConfigWebRTC": { + "type": "object", + "properties": { + "audio_pt": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "force_transcode": { + "type": "boolean" + }, + "video_pt": { + "type": "integer" + } + } + }, "api.ProcessReport": { "type": "object", "properties": { @@ -4434,6 +4555,9 @@ "version": { "type": "integer", "format": "int64" + }, + "webrtc": { + "$ref": "#/definitions/config.DataWebRTC" } } }, @@ -4702,6 +4826,27 @@ } } }, + "config.DataWebRTC": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "nat_1_to_1_ips": { + "type": "array", + "items": { + "type": "string" + } + }, + "public_ip": { + "type": "string" + }, + "udp_mux_port": { + "type": "integer", + "format": "int" + } + } + }, "github_com_datarhei_core_v16_http_api.Config": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ffe87a6..959fe45 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -420,6 +420,8 @@ definitions: version: format: int64 type: integer + webrtc: + $ref: '#/definitions/config.DataWebRTC' type: object api.ConfigError: additionalProperties: @@ -743,6 +745,8 @@ definitions: - ffmpeg - "" type: string + webrtc: + $ref: '#/definitions/api.ProcessConfigWebRTC' required: - input - output @@ -790,6 +794,17 @@ definitions: format: uint64 type: integer type: object + api.ProcessConfigWebRTC: + properties: + audio_pt: + type: integer + enabled: + type: boolean + force_transcode: + type: boolean + video_pt: + type: integer + type: object api.ProcessReport: properties: created_at: @@ -1709,6 +1724,8 @@ definitions: version: format: int64 type: integer + webrtc: + $ref: '#/definitions/config.DataWebRTC' type: object api.Skills: properties: @@ -1882,6 +1899,20 @@ definitions: uptime: type: integer type: object + config.DataWebRTC: + properties: + enable: + type: boolean + nat_1_to_1_ips: + items: + type: string + type: array + public_ip: + type: string + udp_mux_port: + format: int + type: integer + type: object github_com_datarhei_core_v16_http_api.Config: properties: config: @@ -3186,6 +3217,73 @@ paths: summary: List all publishing SRT treams tags: - v16.9.0 + /api/v3/whep/{id}: + post: + consumes: + - application/sdp + description: 'Subscribe to a process''s WebRTC egress stream. Body is the SDP + offer (Content-Type: application/sdp). Response is the SDP answer; the Location + header points at the DELETE resource for teardown.' + operationId: webrtc-3-whep-subscribe + parameters: + - description: Process ID with config.webrtc.enabled=true + in: path + name: id + required: true + type: string + produces: + - application/sdp + responses: + "201": + description: SDP answer + schema: + type: string + "400": + description: missing stream id, malformed body, or invalid SDP + schema: + type: string + "404": + description: no stream registered for this process id + schema: + type: string + "503": + description: peer cap reached + schema: + type: string + security: + - ApiKeyAuth: [] + summary: Subscribe to a WebRTC stream via WHEP + tags: + - v16.16.0 + /api/v3/whep/{id}/{resource}: + delete: + description: 'Tear down a WebRTC peer connection by its resource id (returned + in the Location header by Subscribe). Idempotent: returns 204 even when the + resource is unknown, per the WHEP spec.' + operationId: webrtc-3-whep-unsubscribe + parameters: + - description: Process ID + in: path + name: id + required: true + type: string + - description: Resource ID from the Subscribe Location header + in: path + name: resource + required: true + type: string + responses: + "204": + description: no content + "400": + description: missing resource id + schema: + type: string + security: + - ApiKeyAuth: [] + summary: Tear down a WHEP subscription + tags: + - v16.16.0 /api/v3/widget/process/{id}: get: description: Fetch minimal statistics about a process, which is not protected