mediamtx/internal/core/keepalive.go
Travis Hairfield 1c23d22bbe api: add keepalive endpoints to maintain stream connections
Add keepalive API endpoints that allow streams to be kept active
without real viewers. Keepalives act as synthetic readers that
trigger on-demand publishers and prevent streams from closing when
all real viewers disconnect.

Features:
- POST /v3/paths/keepalive/add/{name} - create keepalive for path
- DELETE /v3/paths/keepalive/remove/{id} - remove keepalive by ID
- GET /v3/paths/keepalive/list - list all active keepalives
- GET /v3/paths/keepalive/get/{id} - get keepalive details

Implementation details:
- Keepalives implement defs.Reader interface
- Full authentication and authorization support
- Ownership tracking - only creator can remove keepalive
- Automatic cleanup when paths are removed
- UUID-based identification
- Asynchronous stream initialization to prevent deadlocks
2025-11-13 16:26:28 -08:00

63 lines
1.5 KiB
Go

package core
import (
"net"
"time"
"github.com/google/uuid"
"github.com/bluenviron/mediamtx/internal/defs"
"github.com/bluenviron/mediamtx/internal/logger"
)
// keepalive is a synthetic reader that keeps a stream alive
// without being an actual viewer.
type keepalive struct {
id uuid.UUID
pathName string
created time.Time
creatorUser string // username that created this keepalive
creatorIP net.IP // IP address that created this keepalive
onClose func() // callback to remove from path when closed
}
func newKeepalive(pathName string, user string, ip net.IP) *keepalive {
return &keepalive{
id: uuid.New(),
pathName: pathName,
created: time.Now(),
creatorUser: user,
creatorIP: ip,
}
}
// Close implements defs.Reader.
// This is called when the keepalive is explicitly closed via the API.
func (k *keepalive) Close() {
if k.onClose != nil {
k.onClose()
}
}
// APIReaderDescribe implements defs.Reader.
func (k *keepalive) APIReaderDescribe() defs.APIPathSourceOrReader {
return defs.APIPathSourceOrReader{
Type: "keepalive",
ID: k.id.String(),
}
}
// Log implements logger.Writer.
func (k *keepalive) Log(level logger.Level, format string, args ...interface{}) {
// no-op, keepalives don't need logging
}
func (k *keepalive) apiDescribe() *defs.APIKeepalive {
return &defs.APIKeepalive{
ID: k.id,
Created: k.created,
Path: k.pathName,
CreatorUser: k.creatorUser,
CreatorIP: k.creatorIP.String(),
}
}