fix: update WebRTC SDP handling and logging for offer/answer exchange

This commit is contained in:
gari 2025-04-13 11:21:09 +02:00
parent 3d88b76c0d
commit 4419e31503

View file

@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"github.com/go-gst/go-glib/glib" "github.com/go-gst/go-glib/glib"
"github.com/go-gst/go-gst/gst" "github.com/go-gst/go-gst/gst"
"github.com/go-gst/go-gst/gst/gstsdp"
"github.com/go-gst/go-gst/gst/gstwebrtc"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -94,7 +96,7 @@ func (api *API) previewHandler(c echo.Context) error {
// on-negotiation-needed: Triggered when webrtcbin needs to create an offer or answer. // on-negotiation-needed: Triggered when webrtcbin needs to create an offer or answer.
// In our case (server receiving an offer), this fires after the remote description is set. // In our case (server receiving an offer), this fires after the remote description is set.
previewPipeline.webrtcbin.Connect("on-negotiation-needed", func(self *gst.Element) { previewPipeline.webrtcbin.Connect("on-negotiation-needed", func(self *gst.Element) {
log.Info().Msg("🧠 Negotiation needed, creating answer...") log.Info().Msg("Negotiation needed, creating answer")
// Create Answer // Create Answer
promise, err := self.Emit("create-answer") promise, err := self.Emit("create-answer")
@ -108,26 +110,26 @@ func (api *API) previewHandler(c echo.Context) error {
} }
// Handle the promise result (asynchronously) // Handle the promise result (asynchronously)
promise.(*gst.Promise).Interrupt() // Interrupt any previous waits promise.(*gst.Promise).Interrupt() // Interrupt any previous waits
promise.(*gst.Promise).Wait() // Wait for the answer to be created promise.(*gst.Promise).Await(c.Request().Context()) // Wait for the answer to be created
reply := promise.(*gst.Promise).GetReply() reply := promise.(*gst.Promise).GetReply()
if reply == nil { if reply == nil {
log.Error().Msg("Promise reply for create-answer was nil") log.Error().Msg("Promise reply for create-answer was nil")
return return
} }
answerValue, ok := reply.GetValue("answer") answerValue, err := reply.GetValue("answer")
if !ok || answerValue == nil { if err != nil || answerValue == nil {
log.Error().Msg("Failed to get answer from promise reply") log.Error().Msg("Failed to get answer from promise reply")
return return
} }
answer, ok := answerValue.(*gst.WebRTCSessionDescription) answer, ok := answerValue.(*gstwebrtc.SessionDescription)
if !ok || answer == nil { if !ok || answer == nil {
log.Error().Msg("Answer value is not a WebRTCSessionDescription") log.Error().Msg("Answer value is not a WebRTCSessionDescription")
return return
} }
log.Debug().Str("sdp", answer.GetSDP().String()).Msg("Answer created") log.Debug().Str("sdp", answer.SDP().String()).Msg("Answer created")
// Set Local Description // Set Local Description
promise, err = self.Emit("set-local-description", answer) promise, err = self.Emit("set-local-description", answer)
@ -141,13 +143,13 @@ func (api *API) previewHandler(c echo.Context) error {
} }
promise.(*gst.Promise).Interrupt() // Interrupt any previous waits promise.(*gst.Promise).Interrupt() // Interrupt any previous waits
log.Info().Msg("➡️ Set local description (answer)") log.Info().Msg("Set local description (answer)")
// Send Answer back to the client // Send Answer back to the client
log.Info().Msg("📨 Sending SDP answer back to browser") log.Info().Msg("Sending SDP answer back to browser")
response := SignalMessage{ response := SignalMessage{
Type: "answer", Type: "answer",
SDP: answer.GetSDP().String(), SDP: answer.SDP().String(),
} }
msg, err := json.Marshal(response) msg, err := json.Marshal(response)
if err != nil { if err != nil {
@ -185,7 +187,7 @@ func (api *API) previewHandler(c echo.Context) error {
// --- WebSocket Message Loop --- // --- WebSocket Message Loop ---
for { for {
messageType, message, err := conn.ReadMessage() _, message, err := conn.ReadMessage()
if err != nil { if err != nil {
log.Error().Err(err).Msg("WebSocket read error") log.Error().Err(err).Msg("WebSocket read error")
break break
@ -199,20 +201,21 @@ func (api *API) previewHandler(c echo.Context) error {
switch signal.Type { switch signal.Type {
case "offer": case "offer":
log.Info().Msg("📥 Received SDP offer from browser") log.Info().Msg("Received SDP offer from browser")
log.Debug().Str("sdp", signal.SDP).Msg("Offer SDP") //log.Debug().Str("sdp", signal.SDP).Msg("Offer SDP")
// Create WebRTCSessionDescription for the offer // Create WebRTCSessionDescription for the offer
offerDesc, err := gst.NewWebRTCSessionDescription(gst.WebRTCSDPTypeOffer, gst.NewSDPMessageFromString(signal.SDP)) offerMsg, err := gstsdp.ParseSDPMessage(signal.SDP)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to create offer description from SDP") log.Error().Err(err).Msg("Failed to parse SDP message")
continue continue
} }
offerDesc := gstwebrtc.NewSessionDescription(gstwebrtc.SDP_TYPE_OFFER, offerMsg)
promise := gst.NewPromise()
// Set Remote Description // Set Remote Description
// This will trigger on-negotiation-needed if successful and state allows // This will trigger on-negotiation-needed if successful and state allows
promise, err := previewPipeline.webrtcbin.Emit("set-remote-description", offerDesc) if _, err := previewPipeline.webrtcbin.Emit("set-remote-description", offerDesc, promise); err != nil {
if err != nil {
log.Error().Err(err).Msg("Failed to emit set-remote-description") log.Error().Err(err).Msg("Failed to emit set-remote-description")
continue continue
} }
@ -220,9 +223,10 @@ func (api *API) previewHandler(c echo.Context) error {
log.Error().Msg("Emit set-remote-description returned nil promise") log.Error().Msg("Emit set-remote-description returned nil promise")
continue continue
} }
promise.(*gst.Promise).Interrupt() // Interrupt previous waits if any //promise.Interrupt() // Interrupt previous waits if any
promise.Await(c.Request().Context()) // Wait for the remote description to be set
log.Info().Msg("➡️ Set remote description (offer)") log.Info().Msg("Set remote description (offer)")
// Answer creation is now handled in on-negotiation-needed // Answer creation is now handled in on-negotiation-needed
case "ice": case "ice":
@ -230,7 +234,7 @@ func (api *API) previewHandler(c echo.Context) error {
log.Warn().Msg("Received ICE signal with nil ICE field") log.Warn().Msg("Received ICE signal with nil ICE field")
continue continue
} }
log.Debug().Str("candidate", signal.ICE.Candidate).Uint16("mlineindex", signal.ICE.SDPMLineIndex).Str("sdpMid", signal.ICE.SDPMid).Msg(" Received ICE candidate from browser") log.Debug().Str("candidate", signal.ICE.Candidate).Uint16("mlineindex", signal.ICE.SDPMLineIndex).Str("sdpMid", signal.ICE.SDPMid).Msg("Received ICE candidate from browser")
// Add ICE Candidate // Add ICE Candidate
// Note: The signal takes mlineindex (uint) and candidate (string). // Note: The signal takes mlineindex (uint) and candidate (string).