Files
monibuca/plugin/gb28181/pkg/sdputil.go
T

194 lines
4.7 KiB
Go

package gb28181
import (
"fmt"
"strconv"
"strings"
"github.com/emiago/sipgo/sip"
)
// DecodeSDP 从 SIP 请求中解析 SDP 信息
func DecodeSDP(req *sip.Request) (*InviteInfo, error) {
inviteInfo := NewInviteInfo()
// 获取请求者ID
from := req.From()
if from == nil || from.Address.User == "" {
return nil, fmt.Errorf("无法从请求中获取来源id")
}
inviteInfo.RequesterId = from.Address.User
// 获取目标通道ID
channelIDArray := getChannelIDFromRequest(req)
// 获取CallID
callID := req.CallID()
if callID != nil {
inviteInfo.CallId = callID.Value()
}
// 解析SDP消息
sdpStr := string(req.Body())
if sdpStr == "" {
return nil, fmt.Errorf("SDP内容为空")
}
// 解析SDP各个字段
lines := strings.Split(sdpStr, "\r\n")
var channelIdFromSdp string
var port int = -1
var mediaTransmissionTCP bool
var tcpActive *bool
var supportedMediaFormat bool
var sessionName string
for _, line := range lines {
if line == "" {
continue
}
switch {
case strings.HasPrefix(line, "s="):
sessionName = strings.TrimPrefix(line, "s=")
inviteInfo.SessionName = sessionName
// 如果是回放,从URI中获取通道ID
if strings.EqualFold(sessionName, "Playback") {
for _, l := range lines {
if strings.HasPrefix(l, "u=") {
uriField := strings.TrimPrefix(l, "u=")
parts := strings.Split(uriField, ":")
if len(parts) > 0 {
channelIdFromSdp = parts[0]
}
break
}
}
}
case strings.HasPrefix(line, "c="):
// c=IN IP4 192.168.1.100
parts := strings.Split(line, " ")
if len(parts) >= 3 {
inviteInfo.IP = parts[2]
}
case strings.HasPrefix(line, "t="):
// t=开始时间 结束时间
parts := strings.Split(strings.TrimPrefix(line, "t="), " ")
if len(parts) >= 2 {
startTime, err := strconv.ParseInt(parts[0], 10, 64)
if err == nil {
inviteInfo.StartTime = startTime
}
stopTime, err := strconv.ParseInt(parts[1], 10, 64)
if err == nil {
inviteInfo.StopTime = stopTime
}
}
case strings.HasPrefix(line, "m="):
mediaDesc := strings.Split(strings.TrimPrefix(line, "m="), " ")
if len(mediaDesc) >= 4 { // 必须有足够的元素:类型、端口、传输协议和格式
portVal, err := strconv.Atoi(mediaDesc[1])
if err == nil {
port = portVal
}
// 检查传输协议
if strings.EqualFold(mediaDesc[2], "TCP/RTP/AVP") {
mediaTransmissionTCP = true
}
// 检查是否包含支持的媒体格式:96或8
for i := 3; i < len(mediaDesc); i++ {
if mediaDesc[i] == "96" || mediaDesc[i] == "8" {
supportedMediaFormat = true
break
}
}
}
case strings.HasPrefix(line, "a=setup:"):
val := strings.TrimPrefix(line, "a=setup:")
if strings.EqualFold(val, "active") {
activeVal := true
tcpActive = &activeVal
} else if strings.EqualFold(val, "passive") {
passiveVal := false
tcpActive = &passiveVal
}
case strings.HasPrefix(line, "y="):
inviteInfo.SSRC = strings.TrimPrefix(line, "y=")
case strings.HasPrefix(line, "a=downloadspeed:"):
inviteInfo.DownloadSpeed = strings.TrimPrefix(line, "a=downloadspeed:")
}
}
// 确定最终的通道ID,优先使用SDP中的通道ID
var finalChannelId string
if channelIdFromSdp != "" {
finalChannelId = channelIdFromSdp
} else if len(channelIDArray) > 0 {
finalChannelId = channelIDArray[0]
}
// 验证通道ID和请求者ID
if inviteInfo.RequesterId == "" || finalChannelId == "" {
return nil, fmt.Errorf("无法从请求中获取通道id或来源id")
}
// 设置目标通道ID
inviteInfo.TargetChannelId = finalChannelId
// 设置源通道ID(如果有)
if len(channelIDArray) >= 2 {
inviteInfo.SourceChannelId = channelIDArray[1]
}
// 验证媒体格式支持
if port == -1 || !supportedMediaFormat {
return nil, fmt.Errorf("不支持的媒体格式")
}
// 设置传输相关信息
inviteInfo.TCP = mediaTransmissionTCP
if tcpActive != nil {
inviteInfo.TCPActive = *tcpActive
} else {
inviteInfo.TCPActive = false // 默认值
}
inviteInfo.Port = port
return inviteInfo, nil
}
// getChannelIDFromRequest 从请求中获取通道ID
func getChannelIDFromRequest(req *sip.Request) []string {
subjectHeaders := req.GetHeaders("Subject")
if len(subjectHeaders) == 0 {
// 如果缺失subject
return nil
}
// 获取第一个Subject头部的值
subjectStr := subjectHeaders[0].Value()
result := make([]string, 2)
if strings.Contains(subjectStr, ",") {
subjectSplit := strings.Split(subjectStr, ",")
result[0] = strings.Split(subjectSplit[0], ":")[0]
if len(subjectSplit) > 1 {
result[1] = strings.Split(subjectSplit[1], ":")[0]
}
} else {
result[0] = strings.Split(subjectStr, ":")[0]
}
return result
}