package api import ( "bufio" "context" "net/http" "os/exec" "time" ffprobe "github.com/datarhei/core/v16/ffmpeg/probe" "github.com/datarhei/core/v16/log" "github.com/labstack/echo/v4" ) // NDIHandler provides an endpoint to discover NDI sources via ffmpeg type NDIHandler struct { logger log.Logger } // NewNDI returns a new NDIHandler func NewNDI() *NDIHandler { return &NDIHandler{ logger: log.New("NDI"), } } // SourcesResponse represents a discovered source type SourcesResponse struct { Address string `json:"address"` Format string `json:"format"` } // Sources runs ffmpeg to find NDI sources and returns parsed inputs func (h *NDIHandler) Sources(c echo.Context) error { ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second) defer cancel() // ffmpeg prints diagnostics on stderr cmd := exec.CommandContext(ctx, "ffmpeg", "-hide_banner", "-nostdin", "-loglevel", "info", "-f", "libndi_newtek", "-find_sources", "1", "-i", "dummy", "-t", "0.5", "-f", "null", "-") sd, err := cmd.StderrPipe() if err != nil { return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } p := ffprobe.New(ffprobe.Config{Logger: h.logger}) if err := cmd.Start(); err != nil { return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) } scanner := bufio.NewScanner(sd) for scanner.Scan() { line := scanner.Text() p.Parse(line) } _ = cmd.Wait() // Parse collected data p.ResetStats() probe := p.Probe() out := make([]SourcesResponse, 0, len(probe.Streams)) for _, s := range probe.Streams { out = append(out, SourcesResponse{ Address: s.Address, Format: s.Format, }) } return c.JSON(http.StatusOK, out) }