golang实现会话描述协议(SDP)解析与生成的插件库sdp的使用
Golang实现会话描述协议(SDP)解析与生成的插件库sdp的使用
简介
Package sdp实现了SDP: 会话描述协议 [RFC4566]。作为核心包,它遵循gortc原则。
![Master status] ![codecov] ![GoDoc]
示例
SDP示例
v=0
o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
s=SDP Seminar
i=A Seminar on the session description protocol
u=http://www.example.com/seminars/sdp.pdf
e=j.doe@example.com (Jane Doe)
p=12345
c=IN IP4 224.2.17.12/127
b=CT:154798
t=2873397496 2873404696
r=7d 1h 0 25h
k=clear:ab8c4df8b8f4as8v8iuy8re
a=recvonly
m=audio 49170 RTP/AVP 0
m=video 51372 RTP/AVP 99
b=AS:66781
k=prompt
a=rtpmap:99 h263-1998/90000
编码示例
package main
import (
"fmt"
"net"
"time"
"gortc.io/sdp"
)
func main() {
var (
s sdp.Session
b []byte
)
// 定义媒体
audio := sdp.Media{
Description: sdp.MediaDescription{
Type: "audio",
Port: 49170,
Formats: []string{"0"},
Protocol: "RTP/AVP",
},
}
video := sdp.Media{
Description: sdp.MediaDescription{
Type: "video",
Port: 51372,
Formats: []string{"99"},
Protocol: "RTP/AVP",
},
Bandwidths: sdp.Bandwidths{
sdp.B bandWidthApplicationSpecific: 66781,
},
Encryption: sdp.Encryption{
Method: "prompt",
},
}
video.AddAttribute("rtpmap", "99", "h263-1998/90000")
// 定义消息
m := &sdp.Message{
Origin: sdp.Origin{
Username: "jdoe",
SessionID: 2890844526,
SessionVersion: 2890842807,
Address: "10.47.16.5",
},
Name: "SDP Seminar",
Info: "A Seminar on the session description protocol",
URI: "http://www.example.com/seminars/sdp.pdf",
Email: "j.doe@example.com (Jane Doe)",
Phone: "12345",
Connection: sdp.ConnectionData{
IP: net.ParseIP("224.2.17.12"),
TTL: 127,
},
Bandwidths: sdp.Bandwidths{
sdp.BandwidthConferenceTotal: 154798,
},
Timing: []sdp.Timing{
{
Start: sdp.NTPToTime(2873397496),
End: sdp.NTPToTime(2873404696),
Repeat: 7 * time.Hour * 24,
Active: 3600 * time.Second,
Offsets: []time.Duration{
0,
25 * time.Hour,
},
},
},
Encryption: sdp.Encryption{
Method: "clear",
Key: "ab8c4df8b8f4as8v8iuy8re",
},
Medias: []sdp.Media{audio, video},
}
m.AddFlag("recvonly")
// 将消息添加到会话
s = m.Append(s)
// 将会话添加到字节缓冲区
b = s.AppendTo(b)
fmt.Println(string(b))
}
解码示例
package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"os"
"gortc.io/sdp"
)
func main() {
name := "example.sdp"
if len(os.Args) > 1 {
name = os.Args[1]
}
var (
s sdp.Session
b []byte
err error
f io.ReadCloser
)
fmt.Println("sdp file:", name)
if f, err = os.Open(name); err != nil {
log.Fatal("err:", err)
}
defer f.Close()
if b, err = ioutil.ReadAll(f); err != nil {
log.Fatal("err:", err)
}
if s, err = sdp.DecodeSession(b, s); err != nil {
log.Fatal("err:", err)
}
for k, v := range s {
fmt.Println(k, v)
}
d := sdp.NewDecoder(s)
m := new(sdp.Message)
if err = d.Decode(m); err != nil {
log.Fatal("err:", err)
}
fmt.Println("Decoded session", m.Name)
fmt.Println("Info:", m.Info)
fmt.Println("Origin:", m.Origin)
}
直接使用Session结构
package main
import (
"fmt"
"gortc.io/sdp"
)
func main() {
var (
s sdp.Session
b []byte
)
b = s.AddVersion(0).
AddMediaDescription(sdp.MediaDescription{
Type: "video",
Port: 51372,
Formats: []string{"99"},
Protocol: "RTP/AVP",
}).
AddAttribute("rtpmap", "99", "h263-1998/90000").
AddLine(sdp.TypeEmail, "test@test.com").
AddRaw('ü', "vαlue").
AppendTo(b)
// 等等
fmt.Println(string(b))
// 输出:
// v=0
// m=video 51372 RTP/AVP 99
// a=rtpmap:99 h263-1998/90000
// e=test@test.com
// ü=vαlue
}
支持的参数
- [x] v (协议版本)
- [x] o (发起者和会话标识符)
- [x] s (会话名称)
- [x] i (会话信息)
- [x] u (描述URI)
- [x] e (电子邮件地址)
- [x] p (电话号码)
- [x] c (连接信息)
- [x] b (零个或多个带宽信息行)
- [x] t (时间)
- [x] r (重复)
- [x] z (时区调整)
- [x] k (加密密钥)
- [x] a (零个或多个会话属性行)
- [x] m (媒体名称和传输地址)
性能基准
goos: linux
goarch: amd64
pkg: github.com/gortc/sdp
PASS
benchmark iter time/iter bytes alloc allocs
--------- ---- --------- ----------- ------
BenchmarkDecoder_Decode-12 300000 4884.00 ns/op 3166 B/op 93 allocs/op
BenchmarkEncode-12 1000000 1577.00 ns/op 0 B/op 0 allocs/op
BenchmarkSession_AddConnectionData-12 20000000 114.00 ns/op 0 B/op 0 allocs/op
BenchmarkAppendIP-12 50000000 37.90 ns/op 0 B/op 0 allocs/op
BenchmarkAppendByte-12 100000000 11.00 ns/op 0 B/op 0 allocs/op
BenchmarkAppendInt-12 100000000 11.90 ns/op 0 B/op 0 allocs/op
BenchmarkSession_EX1-12 3000000 578.00 ns/op 16 B/op 1 allocs/op
BenchmarkAppendRune-12 200000000 6.70 ns/op 0 B/op 0 allocs/op
BenchmarkDecode-12 100000000 13.10 ns/op 0 B/op 0 allocs/op
BenchmarkDecodeSession-12 5000000 234.00 ns/op 0 B/op 0 allocs/op
ok github.com/gortc/sdp 16.820s
更多关于golang实现会话描述协议(SDP)解析与生成的插件库sdp的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现会话描述协议(SDP)解析与生成的插件库sdp的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang SDP 解析与生成库使用指南
会话描述协议(SDP)是多媒体会话描述的标准格式,常用于WebRTC等实时通信场景。在Go语言中,github.com/pion/sdp
是一个优秀的SDP解析与生成库。
安装
go get github.com/pion/sdp/v3
基本用法
解析SDP
package main
import (
"fmt"
"github.com/pion/sdp/v3"
)
func main() {
rawSDP := `v=0
o=- 0 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=audio 4000 RTP/AVP 96
a=rtpmap:96 opus/48000/2
`
s := sdp.SessionDescription{}
if err := s.Unmarshal([]byte(rawSDP)); err != nil {
fmt.Printf("解析SDP失败: %v\n", err)
return
}
fmt.Printf("解析成功! 版本: %s\n", s.Version)
for _, m := range s.MediaDescriptions {
fmt.Printf("媒体类型: %s, 端口: %d, 协议: %s\n",
m.MediaName.Media, m.MediaName.Port.Value, m.MediaName.Protos[0])
}
}
生成SDP
package main
import (
"fmt"
"github.com/pion/sdp/v3"
)
func main() {
s := sdp.SessionDescription{
Version: 0,
Origin: sdp.Origin{
Username: "-",
SessionID: 12345,
SessionVersion: 0,
NetworkType: "IN",
AddressType: "IP4",
UnicastAddress: "127.0.0.1",
},
SessionName: "Example SDP",
ConnectionInformation: &sdp.ConnectionInformation{
NetworkType: "IN",
AddressType: "IP4",
Address: &sdp.Address{Address: "127.0.0.1"},
},
TimeDescriptions: []sdp.TimeDescription{
{Timing: sdp.Timing{StartTime: 0, StopTime: 0}},
},
MediaDescriptions: []*sdp.MediaDescription{
{
MediaName: sdp.MediaName{
Media: "audio",
Port: sdp.RangedPort{Value: 4000},
Protos: []string{"RTP", "AVP"},
Formats: []string{"96"},
},
Attributes: []sdp.Attribute{
{Key: "rtpmap", Value: "96 opus/48000/2"},
},
},
},
}
output, err := s.Marshal()
if err != nil {
fmt.Printf("生成SDP失败: %v\n", err)
return
}
fmt.Printf("生成的SDP:\n%s\n", string(output))
}
高级功能
处理ICE候选信息
func addICECandidate(s *sdp.SessionDescription) {
for _, m := range s.MediaDescriptions {
m.Attributes = append(m.Attributes, sdp.Attribute{
Key: "candidate",
Value: "foundation 1 udp 2130706431 192.168.1.1 4000 typ host",
})
}
}
处理SSRC
func addSSRC(m *sdp.MediaDescription, ssrc uint32) {
m.Attributes = append(m.Attributes, sdp.Attribute{
Key: "ssrc",
Value: fmt.Sprintf("%d cname:user@example.com", ssrc),
})
}
处理带宽信息
func addBandwidth(s *sdp.SessionDescription, bwType string, value int) {
s.Bandwidth = append(s.Bandwidth, sdp.Bandwidth{
Experimental: false,
Type: bwType,
Bandwidth: uint64(value),
})
}
实际应用示例
package main
import (
"fmt"
"github.com/pion/sdp/v3"
)
func createWebRTCSDP() string {
s := sdp.SessionDescription{
Version: 0,
Origin: sdp.Origin{
Username: "-",
SessionID: 123456789,
SessionVersion: 1,
NetworkType: "IN",
AddressType: "IP4",
UnicastAddress: "127.0.0.1",
},
SessionName: "WebRTC Session",
ConnectionInformation: &sdp.ConnectionInformation{
NetworkType: "IN",
AddressType: "IP4",
Address: &sdp.Address{Address: "0.0.0.0"},
},
TimeDescriptions: []sdp.TimeDescription{
{Timing: sdp.Timing{StartTime: 0, StopTime: 0}},
},
MediaDescriptions: []*sdp.MediaDescription{
{
MediaName: sdp.MediaName{
Media: "audio",
Port: sdp.RangedPort{Value: 9},
Protos: []string{"UDP", "TLS", "RTP", "SAVPF"},
Formats: []string{"111", "103", "104", "9", "0", "8", "106", "105", "13", "110", "112", "113", "126"},
},
Attributes: []sdp.Attribute{
{Key: "rtpmap", Value: "111 opus/48000/2"},
{Key: "fmtp", Value: "111 minptime=10;useinbandfec=1"},
{Key: "rtpmap", Value: "103 ISAC/16000"},
{Key: "rtpmap", Value: "104 ISAC/32000"},
{Key: "rtpmap", Value: "9 G722/8000"},
{Key: "rtpmap", Value: "0 PCMU/8000"},
{Key: "rtpmap", Value: "8 PCMA/8000"},
{Key: "rtpmap", Value: "106 CN/32000"},
{Key: "rtpmap", Value: "105 CN/16000"},
{Key: "rtpmap", Value: "13 CN/8000"},
{Key: "rtpmap", Value: "110 telephone-event/48000"},
{Key: "rtpmap", Value: "112 telephone-event/32000"},
{Key: "rtpmap", Value: "113 telephone-event/16000"},
{Key: "rtpmap", Value: "126 telephone-event/8000"},
{Key: "ssrc", Value: "12345678 cname:user@example.com"},
{Key: "ice-ufrag", Value: "abc123"},
{Key: "ice-pwd", Value: "def456"},
{Key: "fingerprint", Value: "sha-256 12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF"},
{Key: "setup", Value: "actpass"},
{Key: "mid", Value: "audio"},
{Key: "sendrecv"},
},
},
},
}
output, _ := s.Marshal()
return string(output)
}
func main() {
sdpStr := createWebRTCSDP()
fmt.Println("生成的WebRTC SDP:")
fmt.Println(sdpStr)
}
注意事项
- 解析时注意错误处理,SDP格式严格
- 生成时确保必填字段完整(version, origin, session name等)
- 对于WebRTC应用,需要包含ICE和DTLS相关属性
- 媒体描述的顺序会影响协商结果
pion/sdp
库提供了完整的SDP解析和生成能力,适合各种实时通信应用的开发。