Skip to main content

Overview

The SessionDescription type is used to expose local and remote session descriptions. It encapsulates the Session Description Protocol (SDP) information exchanged between peers during connection establishment.
Source: sessiondescription.go:39-46

Type Definition

type SessionDescription struct {
    Type   SDPType
    SDP    string
    parsed *sdp.SessionDescription // Internal use only
}
Type
SDPType
The type of session description (offer, answer, pranswer, or rollback)
SDP
string
The SDP string content
parsed
*sdp.SessionDescription
Internal parsed representation (not initialized by callers)

SDPType Enumeration

The SDPType describes the type of a SessionDescription.
Source: sdptype.go:11-39
type SDPType int

const (
    SDPTypeUnknown  SDPType = iota  // Zero-value, invalid
    SDPTypeOffer                     // SDP offer
    SDPTypePranswer                  // Provisional answer
    SDPTypeAnswer                    // Final answer
    SDPTypeRollback                  // Cancel negotiation
)

SDPTypeOffer

SDPTypeOffer
SDPType
Indicates that a description MUST be treated as an SDP offer.
Used when initiating a connection or renegotiating.
offer, err := pc.CreateOffer(nil)
if err != nil {
    return err
}

fmt.Println(offer.Type) // Output: offer

SDPTypePranswer

SDPTypePranswer
SDPType
Indicates that a description MUST be treated as an SDP provisional answer, but not a final answer.
A pranswer may be applied as a response to an SDP offer, or an update to a previously sent SDP pranswer.
Provisional answers are rarely used in practice. Most applications use immediate final answers.

SDPTypeAnswer

SDPTypeAnswer
SDPType
Indicates that a description MUST be treated as an SDP final answer, and the offer-answer exchange MUST be considered complete.
Used to respond to an offer or update a previously sent pranswer.
answer, err := pc.CreateAnswer(nil)
if err != nil {
    return err
}

fmt.Println(answer.Type) // Output: answer

SDPTypeRollback

SDPTypeRollback
SDPType
Indicates that a description MUST be treated as canceling the current SDP negotiation and moving the SDP offer and answer back to what it was in the previous stable state.
Used to abort a negotiation in progress.
rollback := webrtc.SessionDescription{
    Type: webrtc.SDPTypeRollback,
}

err := pc.SetLocalDescription(rollback)

SDPType Methods

NewSDPType

Creates an SDPType from a string.
Source: sdptype.go:49-63
func NewSDPType(raw string) SDPType
raw
string
String representation (“offer”, “pranswer”, “answer”, or “rollback”)
return
SDPType
The corresponding SDPType, or SDPTypeUnknown if invalid
sdpType := webrtc.NewSDPType("offer")
fmt.Println(sdpType == webrtc.SDPTypeOffer) // true

String

Returns the string representation of an SDPType.
Source: sdptype.go:65-78
func (t SDPType) String() string
return
string
String representation of the SDPType
sdpType := webrtc.SDPTypeOffer
fmt.Println(sdpType.String()) // "offer"

SessionDescription Methods

Unmarshal

A helper to deserialize the SDP.
Source: sessiondescription.go:48-57
func (sd *SessionDescription) Unmarshal() (*sdp.SessionDescription, error)
parsed
*sdp.SessionDescription
Parsed SDP structure
error
error
Error if unmarshaling fails
sd := webrtc.SessionDescription{
    Type: webrtc.SDPTypeOffer,
    SDP:  receivedSDPString,
}

parsed, err := sd.Unmarshal()
if err != nil {
    return err
}
This method is typically used internally. Most application code doesn’t need to call it directly.

Usage with PeerConnection

Creating an Offer

offer, err := pc.CreateOffer(nil)
if err != nil {
    return err
}

// Offer is a SessionDescription with Type = SDPTypeOffer
fmt.Printf("Type: %s\n", offer.Type)
fmt.Printf("SDP: %s\n", offer.SDP)

// Set as local description
err = pc.SetLocalDescription(offer)
if err != nil {
    return err
}

// Send offer.SDP to remote peer via signaling
sendToRemotePeer(offer.SDP)

Handling a Remote Offer

// Receive SDP from remote peer
remoteSDP := receiveFromRemotePeer()

// Create SessionDescription
remoteOffer := webrtc.SessionDescription{
    Type: webrtc.SDPTypeOffer,
    SDP:  remoteSDP,
}

// Set as remote description
err := pc.SetRemoteDescription(remoteOffer)
if err != nil {
    return err
}

// Create and send answer
answer, err := pc.CreateAnswer(nil)
if err != nil {
    return err
}

err = pc.SetLocalDescription(answer)
if err != nil {
    return err
}

sendToRemotePeer(answer.SDP)

Creating an Answer

// After receiving and setting a remote offer
answer, err := pc.CreateAnswer(nil)
if err != nil {
    return err
}

// Answer is a SessionDescription with Type = SDPTypeAnswer
err = pc.SetLocalDescription(answer)
if err != nil {
    return err
}

// Send answer.SDP to remote peer
sendToRemotePeer(answer.SDP)

ICE Trickle Support

The SessionDescription type works with ICE trickle capability detection.
Source: sessiondescription.go:14-37

ICETrickleCapability

type ICETrickleCapability int

const (
    ICETrickleCapabilityUnknown     ICETrickleCapability = iota
    ICETrickleCapabilitySupported
    ICETrickleCapabilityUnsupported
)
ICETrickleCapabilityUnknown
int
No remote peer has been established
ICETrickleCapabilitySupported
int
Remote peer can accept trickled ICE candidates
ICETrickleCapabilityUnsupported
int
Remote peer didn’t state that it can accept trickle ICE candidates
capability := pc.CanTrickleICECandidates()

switch capability {
case webrtc.ICETrickleCapabilitySupported:
    // Can send candidates as they're gathered
    fmt.Println("Trickle ICE supported")
case webrtc.ICETrickleCapabilityUnsupported:
    // Must wait for all candidates before signaling
    fmt.Println("Trickle ICE not supported")
default:
    fmt.Println("Trickle ICE capability unknown")
}

Complete Signaling Example

package main

import (
    "encoding/json"
    "github.com/pion/webrtc/v4"
)

func createOffer(pc *webrtc.PeerConnection, signaling chan []byte) error {
    // Create offer
    offer, err := pc.CreateOffer(nil)
    if err != nil {
        return err
    }

    // Set local description
    err = pc.SetLocalDescription(offer)
    if err != nil {
        return err
    }

    // Marshal and send offer
    offerJSON, err := json.Marshal(offer)
    if err != nil {
        return err
    }
    signaling <- offerJSON

    // Wait for answer
    answerJSON := <-signaling

    // Unmarshal answer
    var answer webrtc.SessionDescription
    err = json.Unmarshal(answerJSON, &answer)
    if err != nil {
        return err
    }

    // Set remote description
    return pc.SetRemoteDescription(answer)
}

Best Practices

Always Set Locally First

Always call SetLocalDescription with the offer/answer you created before sending it to the remote peer.

Error Handling

Check errors from CreateOffer, CreateAnswer, and SetLocalDescription/SetRemoteDescription - they can fail.

Signaling Independence

SessionDescriptions are just data - you choose how to exchange them (WebSocket, HTTP, etc.).

JSON Serialization

SessionDescription has JSON tags and can be marshaled/unmarshaled directly.

Common Patterns

Handle offer collisions gracefully:
func handleNegotiation(pc *webrtc.PeerConnection, isPolite bool) {
    pc.OnNegotiationNeeded(func() {
        offer, err := pc.CreateOffer(nil)
        if err != nil {
            return
        }

        err = pc.SetLocalDescription(offer)
        if err != nil {
            return
        }

        // Send offer
    })

    // On receiving offer
    onOfferReceived := func(offer webrtc.SessionDescription) error {
        // Check for collision
        if pc.SignalingState() != webrtc.SignalingStateStable {
            if !isPolite {
                // Ignore the offer
                return nil
            }
            // Rollback local offer
            err := pc.SetLocalDescription(webrtc.SessionDescription{
                Type: webrtc.SDPTypeRollback,
            })
            if err != nil {
                return err
            }
        }

        err := pc.SetRemoteDescription(offer)
        if err != nil {
            return err
        }

        answer, err := pc.CreateAnswer(nil)
        if err != nil {
            return err
        }

        return pc.SetLocalDescription(answer)
    }
}
Modify SDP before setting (advanced):
offer, err := pc.CreateOffer(nil)
if err != nil {
    return err
}

// Parse the SDP
parsed, err := offer.Unmarshal()
if err != nil {
    return err
}

// Modify bandwidth, add attributes, etc.
for _, media := range parsed.MediaDescriptions {
    media.Bandwidth = append(media.Bandwidth, sdp.Bandwidth{
        Experimental: false,
        Type:         "AS",
        Bandwidth:    1000,
    })
}

// Marshal back to string
modifiedSDP, err := parsed.Marshal()
if err != nil {
    return err
}

offer.SDP = string(modifiedSDP)

// Now set the modified offer
err = pc.SetLocalDescription(offer)
Handle mid-call changes:
// Add a new track mid-call
newTrack, err := webrtc.NewTrackLocalStaticSample(
    webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8},
    "video",
    "pion",
)
if err != nil {
    return err
}

_, err = pc.AddTrack(newTrack)
if err != nil {
    return err
}

// Create new offer for renegotiation
offer, err := pc.CreateOffer(nil)
if err != nil {
    return err
}

err = pc.SetLocalDescription(offer)
if err != nil {
    return err
}

// Send new offer to peer

Troubleshooting

Common causes:
  • SDP format is invalid or corrupted
  • Wrong SDPType for current signaling state
  • Missing media sections that were in previous offer
err := pc.SetRemoteDescription(desc)
if err != nil {
    fmt.Printf("Failed to set remote description: %v\n", err)
    fmt.Printf("Current signaling state: %s\n", pc.SignalingState())
    fmt.Printf("Description type: %s\n", desc.Type)
}
According to JSEP 5.4, you can set an empty SDP string:
// This will use the last created offer
err := pc.SetLocalDescription(webrtc.SessionDescription{
    Type: webrtc.SDPTypeOffer,
    SDP:  "", // Will use last created offer
})

See Also

Build docs developers (and LLMs) love