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 }