golang实现SDP会话描述协议解析与生成的插件库sdpRFC4566的使用

Golang实现SDP会话描述协议解析与生成的插件库sdpRFC4566的使用

简介

Package sdp实现了SDP: Session Description Protocol [RFC4566]。作为gortc核心包,符合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.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 (媒体名称和传输地址)

构建状态

Build Status Build status

许可证

FOSSA Status


更多关于golang实现SDP会话描述协议解析与生成的插件库sdpRFC4566的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现SDP会话描述协议解析与生成的插件库sdpRFC4566的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang实现SDP协议解析与生成的插件库

SDP(会话描述协议)是一种用于描述多媒体会话的协议,常用于WebRTC、VoIP等应用中。在Go语言中,我们可以使用sdp库来解析和生成符合RFC4566标准的SDP数据。

安装sdp库

go get github.com/notedit/sdp

基本用法

解析SDP

package main

import (
	"fmt"
	"github.com/notedit/sdp"
)

func main() {
	sdpStr := `v=0
o=- 0 0 IN IP4 127.0.0.1
s=-
c=IN IP4 127.0.0.1
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000
a=sendrecv
m=video 51372 RTP/AVP 99
a=rtpmap:99 H264/90000
a=fmtp:99 profile-level-id=42e01f;packetization-mode=1
a=sendrecv`

	// 解析SDP
	session, err := sdp.ParseSDP(sdpStr)
	if err != nil {
		panic(err)
	}

	// 打印基本信息
	fmt.Printf("Version: %d\n", session.Version)
	fmt.Printf("Origin: %s\n", session.Origin)
	fmt.Printf("SessionName: %s\n", session.SessionName)
	fmt.Printf("Connection: %s\n", session.Connection)

	// 遍历媒体流
	for _, media := range session.Medias {
		fmt.Printf("\nMedia: %s %d %s\n", media.Type, media.Port, media.Protocol)
		for _, attr := range media.Attributes {
			fmt.Printf("Attribute: %s=%s\n", attr.Key, attr.Value)
		}
	}
}

生成SDP

package main

import (
	"fmt"
	"github.com/notedit/sdp"
)

func main() {
	// 创建新的SDP会话
	session := &sdp.Session{
		Version: 0,
		Origin: sdp.Origin{
			Username:       "-",
			SessionID:      1234567890,
			SessionVersion: 1234567890,
			NetType:        "IN",
			AddrType:       "IP4",
			UnicastAddress: "127.0.0.1",
		},
		SessionName: "Go SDP Example",
		Connection: &sdp.Connection{
			NetType:        "IN",
			AddrType:       "IP4",
			ConnectionAddr: "127.0.0.1",
		},
		Time: &sdp.Time{
			StartTime: 0,
			StopTime:  0,
		},
	}

	// 添加音频媒体流
	audioMedia := &sdp.Media{
		Type:     "audio",
		Port:     49170,
		Protocol: "RTP/AVP",
		Formats:  []string{"0"},
		Attributes: []*sdp.Attribute{
			{Key: "rtpmap", Value: "0 PCMU/8000"},
			{Key: "sendrecv"},
		},
	}
	session.Medias = append(session.Medias, audioMedia)

	// 添加视频媒体流
	videoMedia := &sdp.Media{
		Type:     "video",
		Port:     51372,
		Protocol: "RTP/AVP",
		Formats:  []string{"99"},
		Attributes: []*sdp.Attribute{
			{Key: "rtpmap", Value: "99 H264/90000"},
			{Key: "fmtp", Value: "99 profile-level-id=42e01f;packetization-mode=1"},
			{Key: "sendrecv"},
		},
	}
	session.Medias = append(session.Medias, videoMedia)

	// 生成SDP字符串
	sdpStr := session.String()
	fmt.Println(sdpStr)
}

高级功能

处理ICE候选

// 添加ICE候选
audioMedia.AddAttribute("candidate", "1 1 UDP 2130706431 192.168.1.100 5000 typ host")
audioMedia.AddAttribute("candidate", "2 1 UDP 1694498815 203.0.113.1 5000 typ srflx raddr 192.168.1.100 rport 5000")

处理DTLS指纹

session.AddAttribute("fingerprint", "sha-256 12:DF:3A:...")

处理SSRC

videoMedia.AddAttribute("ssrc", "12345678 cname:user@example.com")

实际应用示例

以下是一个完整的WebRTC SDP生成示例:

func generateWebRTCSDP() string {
	session := &sdp.Session{
		Version: 0,
		Origin: sdp.Origin{
			Username:       "-",
			SessionID:      uint64(time.Now().UnixNano()),
			SessionVersion: uint64(time.Now().UnixNano()),
			NetType:        "IN",
			AddrType:       "IP4",
			UnicastAddress: "127.0.0.1",
		},
		SessionName: "WebRTC",
		Connection: &sdp.Connection{
			NetType:        "IN",
			AddrType:       "IP4",
			ConnectionAddr: "0.0.0.0",
		},
		Time: &sdp.Time{
			StartTime: 0,
			StopTime:  0,
		},
	}

	// 添加音频媒体
	audio := &sdp.Media{
		Type:     "audio",
		Port:     9, // 使用端口9表示不指定端口
		Protocol: "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:audio"},
			{Key: "ssrc", Value: "12345678 msid:audio audio_label"},
			{Key: "ssrc", Value: "12345678 mslabel:audio_label"},
			{Key: "sendrecv"},
		},
	}
	session.Medias = append(session.Medias, audio)

	// 添加视频媒体
	video := &sdp.Media{
		Type:     "video",
		Port:     9,
		Protocol: "UDP/TLS/RTP/SAVPF",
		Formats:  []string{"100", "101", "102", "125", "107", "108", "109", "127", "124", "120", "123", "119", "114", "115", "116", "117", "118"},
		Attributes: []*sdp.Attribute{
			{Key: "rtpmap", Value: "100 VP8/90000"},
			{Key: "rtpmap", Value: "101 VP9/90000"},
			{Key: "rtpmap", Value: "102 H264/90000"},
			{Key: "fmtp", Value: "102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f"},
			{Key: "rtpmap", Value: "125 H264/90000"},
			{Key: "fmtp", Value: "125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f"},
			{Key: "rtpmap", Value: "107 H264/90000"},
			{Key: "fmtp", Value: "107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f"},
			{Key: "rtpmap", Value: "108 H264/90000"},
			{Key: "fmtp", Value: "108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f"},
			{Key: "rtpmap", Value: "109 rtx/90000"},
			{Key: "fmtp", Value: "109 apt=100"},
			{Key: "rtpmap", Value: "127 rtx/90000"},
			{Key: "fmtp", Value: "127 apt=101"},
			{Key: "rtpmap", Value: "124 rtx/90000"},
			{Key: "fmtp", Value: "124 apt=102"},
			{Key: "rtpmap", Value: "120 rtx/90000"},
			{Key: "fmtp", Value: "120 apt=125"},
			{Key: "rtpmap", Value: "123 rtx/90000"},
			{Key: "fmtp", Value: "123 apt=107"},
			{Key: "rtpmap", Value: "119 rtx/90000"},
			{Key: "fmtp", Value: "119 apt=108"},
			{Key: "ssrc", Value: "23456789 cname:video"},
			{Key: "ssrc", Value: "23456789 msid:video video_label"},
			{Key: "ssrc", Value: "23456789 mslabel:video_label"},
			{Key: "sendrecv"},
		},
	}
	session.Medias = append(session.Medias, video)

	// 添加全局属性
	session.AddAttribute("group", "BUNDLE audio video")
	session.AddAttribute("ice-ufrag", "abcdefgh")
	session.AddAttribute("ice-pwd", "1234567890abcdefghijklmnopqrstuv")
	session.AddAttribute("fingerprint", "sha-256 12:DF:3A:...")
	session.AddAttribute("setup", "actpass")

	return session.String()
}

总结

sdp库提供了完整的SDP协议解析和生成功能,可以方便地用于WebRTC、VoIP等多媒体应用中。通过这个库,我们可以:

  1. 解析标准的SDP字符串为结构化的Go对象
  2. 通过Go对象生成符合RFC4566标准的SDP字符串
  3. 方便地添加和修改SDP的各个部分
  4. 支持WebRTC等现代协议扩展

在实际应用中,可以根据需要扩展或封装这个库,以满足特定的业务需求。

回到顶部