github.com/whoyao/protocol@v0.0.0-20230519045905-2d8ace718ca5/sdp/sdp.go (about)

     1  package sdp
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/pion/sdp/v3"
     7  	"github.com/whoyao/webrtc/v3"
     8  )
     9  
    10  func GetMidValue(media *sdp.MediaDescription) string {
    11  	for _, attr := range media.Attributes {
    12  		if attr.Key == sdp.AttrKeyMID {
    13  			return attr.Value
    14  		}
    15  	}
    16  	return ""
    17  }
    18  
    19  func ExtractFingerprint(desc *sdp.SessionDescription) (string, string, error) {
    20  	fingerprints := make([]string, 0)
    21  
    22  	if fingerprint, haveFingerprint := desc.Attribute("fingerprint"); haveFingerprint {
    23  		fingerprints = append(fingerprints, fingerprint)
    24  	}
    25  
    26  	for _, m := range desc.MediaDescriptions {
    27  		if fingerprint, haveFingerprint := m.Attribute("fingerprint"); haveFingerprint {
    28  			fingerprints = append(fingerprints, fingerprint)
    29  		}
    30  	}
    31  
    32  	if len(fingerprints) < 1 {
    33  		return "", "", webrtc.ErrSessionDescriptionNoFingerprint
    34  	}
    35  
    36  	for _, m := range fingerprints {
    37  		if m != fingerprints[0] {
    38  			return "", "", webrtc.ErrSessionDescriptionConflictingFingerprints
    39  		}
    40  	}
    41  
    42  	parts := strings.Split(fingerprints[0], " ")
    43  	if len(parts) != 2 {
    44  		return "", "", webrtc.ErrSessionDescriptionInvalidFingerprint
    45  	}
    46  	return parts[1], parts[0], nil
    47  }
    48  
    49  func ExtractDTLSRole(desc *sdp.SessionDescription) webrtc.DTLSRole {
    50  	for _, md := range desc.MediaDescriptions {
    51  		setup, ok := md.Attribute(sdp.AttrKeyConnectionSetup)
    52  		if !ok {
    53  			continue
    54  		}
    55  
    56  		if setup == sdp.ConnectionRoleActive.String() {
    57  			return webrtc.DTLSRoleClient
    58  		}
    59  
    60  		if setup == sdp.ConnectionRolePassive.String() {
    61  			return webrtc.DTLSRoleServer
    62  		}
    63  	}
    64  
    65  	//
    66  	// If 'setup' attribute is not available, use client role
    67  	// as that is the default behaviour of answerers
    68  	//
    69  	// There seems to be some differences in how role is decided.
    70  	// libwebrtc (Chrome) code - (https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/pc/jsep_transport.cc;l=592;drc=369fb686729e7eb20d2bd09717cec14269a399d7)
    71  	// does not mention anything about ICE role when determining
    72  	// DTLS Role.
    73  	//
    74  	// But, ORTC has this - https://github.com/w3c/ortc/issues/167#issuecomment-69409953
    75  	// and pion/webrtc follows that (https://github.com/pion/webrtc/blob/e071a4eded1efd5d9b401bcfc4efacb3a2a5a53c/dtlstransport.go#L269)
    76  	//
    77  	// So if remote is ice-lite, pion will use DTLSRoleServer when answering
    78  	// while browsers pick DTLSRoleClient.
    79  	//
    80  	return webrtc.DTLSRoleClient
    81  }
    82  
    83  func ExtractICECredential(desc *sdp.SessionDescription) (string, string, error) {
    84  	remotePwds := []string{}
    85  	remoteUfrags := []string{}
    86  
    87  	if ufrag, haveUfrag := desc.Attribute("ice-ufrag"); haveUfrag {
    88  		remoteUfrags = append(remoteUfrags, ufrag)
    89  	}
    90  	if pwd, havePwd := desc.Attribute("ice-pwd"); havePwd {
    91  		remotePwds = append(remotePwds, pwd)
    92  	}
    93  
    94  	for _, m := range desc.MediaDescriptions {
    95  		if ufrag, haveUfrag := m.Attribute("ice-ufrag"); haveUfrag {
    96  			remoteUfrags = append(remoteUfrags, ufrag)
    97  		}
    98  		if pwd, havePwd := m.Attribute("ice-pwd"); havePwd {
    99  			remotePwds = append(remotePwds, pwd)
   100  		}
   101  	}
   102  
   103  	if len(remoteUfrags) == 0 {
   104  		return "", "", webrtc.ErrSessionDescriptionMissingIceUfrag
   105  	} else if len(remotePwds) == 0 {
   106  		return "", "", webrtc.ErrSessionDescriptionMissingIcePwd
   107  	}
   108  
   109  	for _, m := range remoteUfrags {
   110  		if m != remoteUfrags[0] {
   111  			return "", "", webrtc.ErrSessionDescriptionConflictingIceUfrag
   112  		}
   113  	}
   114  
   115  	for _, m := range remotePwds {
   116  		if m != remotePwds[0] {
   117  			return "", "", webrtc.ErrSessionDescriptionConflictingIcePwd
   118  		}
   119  	}
   120  
   121  	return remoteUfrags[0], remotePwds[0], nil
   122  }
   123  
   124  func ExtractStreamID(media *sdp.MediaDescription) (string, bool) {
   125  	// last video is pending for publish, set codec preference
   126  	var streamID string
   127  	msid, ok := media.Attribute(sdp.AttrKeyMsid)
   128  	if !ok {
   129  		return "", false
   130  	}
   131  	ids := strings.Split(msid, " ")
   132  	if len(ids) < 2 {
   133  		streamID = msid
   134  	} else {
   135  		streamID = ids[1]
   136  	}
   137  	return streamID, true
   138  }