增加对纯音频的播放的支持

This commit is contained in:
langhuihui
2020-08-27 08:50:45 +08:00
parent fd64a69a12
commit 1d3fbfc20b
4 changed files with 67 additions and 91 deletions

View File

@@ -30,6 +30,7 @@ func (rtsp *RTSP) PullStream(streamPath string, rtspUrl string) (err error) {
rtsp.aRTPChannel = 2 rtsp.aRTPChannel = 2
rtsp.aRTPControlChannel = 3 rtsp.aRTPControlChannel = 3
rtsp.URL = rtspUrl rtsp.URL = rtspUrl
rtsp.UDPServer = &UDPServer{Session: rtsp}
if err = rtsp.requestStream(); err != nil { if err = rtsp.requestStream(); err != nil {
Println(err) Println(err)
rtsp.Close() rtsp.Close()
@@ -189,86 +190,65 @@ func (client *RTSP) requestStream() (err error) {
} }
client.SDPRaw = resp.Body client.SDPRaw = resp.Body
client.SDPMap = ParseSDP(client.SDPRaw) client.SDPMap = ParseSDP(client.SDPRaw)
client.VSdp, client.HasVideo = client.SDPMap["video"]
client.ASdp, client.HasAudio = client.SDPMap["audio"]
session := "" session := ""
if videoInfo, ok := client.SDPMap["video"]; ok { otherChannel := 4
for i := 0; i < len(videoInfo.Control); i++ { for t, sdpInfo := range client.SDPMap {
client.VControl = videoInfo.Control[i] headers = make(map[string]string)
client.VCodec = videoInfo.Codec if session != "" {
client.WriteSPS(videoInfo.SpropParameterSets[0]) headers["Session"] = session
client.WritePPS(videoInfo.SpropParameterSets[1]) }
var _url = "" var _url = sdpInfo.Control
if strings.Index(strings.ToLower(client.VControl), "rtsp://") == 0 { if !strings.HasPrefix(strings.ToLower(sdpInfo.Control), "rtsp://") {
_url = client.VControl _url = strings.TrimRight(client.URL, "/") + "/" + strings.TrimLeft(sdpInfo.Control, "/")
} else { }
_url = strings.TrimRight(client.URL, "/") + "/" + strings.TrimLeft(client.VControl, "/") switch t {
case "video":
if len(sdpInfo.SpropParameterSets) > 1 {
client.WriteSPS(sdpInfo.SpropParameterSets[0])
client.WritePPS(sdpInfo.SpropParameterSets[1])
} }
headers = make(map[string]string)
if client.TransType == TRANS_TYPE_TCP { if client.TransType == TRANS_TYPE_TCP {
headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", client.vRTPChannel, client.vRTPControlChannel) headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", client.vRTPChannel, client.vRTPControlChannel)
} else { } else {
if client.UDPServer == nil {
client.UDPServer = &UDPServer{Session: client}
}
//RTP/AVP;unicast;client_port=64864-64865 //RTP/AVP;unicast;client_port=64864-64865
err = client.UDPServer.SetupVideo() if err = client.UDPServer.SetupVideo(); err != nil {
if err != nil {
Printf("Setup video err.%v", err) Printf("Setup video err.%v", err)
return err return err
} }
headers["Transport"] = fmt.Sprintf("RTP/AVP/UDP;unicast;client_port=%d-%d", client.UDPServer.VPort, client.UDPServer.VControlPort) headers["Transport"] = fmt.Sprintf("RTP/AVP/UDP;unicast;client_port=%d-%d", client.UDPServer.VPort, client.UDPServer.VControlPort)
client.Conn.timeout = 0 // UDP ignore timeout client.Conn.timeout = 0 // UDP ignore timeout
} }
if session != "" { case "audio":
headers["Session"] = session if len(sdpInfo.Config) < 2 {
} Printf("Setup audio err codec not support: %s", client.ASdp.Codec)
Printf("Parse DESCRIBE response, VIDEO VControl:%s, VCode:%s, url:%s,Session:%s,vRTPChannel:%d,vRTPControlChannel:%d", client.VControl, client.VCodec, _url, session, client.vRTPChannel, client.vRTPControlChannel)
if resp, err = client.RequestWithPath("SETUP", _url, headers, true); err != nil {
return err
}
session, _ = resp.Header["Session"].(string)
session = strings.Split(session, ";")[0]
}
}
if audioInfo, ok := client.SDPMap["audio"]; ok {
for i := 0; i < len(audioInfo.Control); i++ {
client.AControl = audioInfo.Control[i]
client.ACodec = audioInfo.Codec
if len(audioInfo.Config) < 2 {
Printf("Setup audio err codec not support: %s", client.ACodec)
} else { } else {
client.WriteASC(audioInfo.Config) client.WriteASC(sdpInfo.Config)
} }
var _url = ""
if strings.Index(strings.ToLower(client.AControl), "rtsp://") == 0 {
_url = client.AControl
} else {
_url = strings.TrimRight(client.URL, "/") + "/" + strings.TrimLeft(client.AControl, "/")
}
headers = make(map[string]string)
if client.TransType == TRANS_TYPE_TCP { if client.TransType == TRANS_TYPE_TCP {
headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", client.aRTPChannel, client.aRTPControlChannel) headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", client.aRTPChannel, client.aRTPControlChannel)
} else { } else {
if client.UDPServer == nil { if err = client.UDPServer.SetupAudio(); err != nil {
client.UDPServer = &UDPServer{Session: client}
}
err = client.UDPServer.SetupAudio()
if err != nil {
Printf("Setup audio err.%v", err) Printf("Setup audio err.%v", err)
return err return err
} }
headers["Transport"] = fmt.Sprintf("RTP/AVP/UDP;unicast;client_port=%d-%d", client.UDPServer.APort, client.UDPServer.AControlPort) headers["Transport"] = fmt.Sprintf("RTP/AVP/UDP;unicast;client_port=%d-%d", client.UDPServer.APort, client.UDPServer.AControlPort)
client.Conn.timeout = 0 // UDP ignore timeout client.Conn.timeout = 0 // UDP ignore timeout
} }
if session != "" { default:
headers["Session"] = session if client.TransType == TRANS_TYPE_TCP {
headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", otherChannel, otherChannel+1)
otherChannel += 2
} else {
//TODO: UDP support
} }
Printf("Parse DESCRIBE response, AUDIO AControl:%s, ACodec:%s, url:%s,Session:%s, aRTPChannel:%d,aRTPControlChannel:%d", client.AControl, client.ACodec, _url, session, client.aRTPChannel, client.aRTPControlChannel)
if resp, err = client.RequestWithPath("SETUP", _url, headers, true); err != nil {
return err
}
session, _ = resp.Header["Session"].(string)
session = strings.Split(session, ";")[0]
} }
if resp, err = client.RequestWithPath("SETUP", _url, headers, true); err != nil {
return err
}
session, _ = resp.Header["Session"].(string)
session = strings.Split(session, ";")[0]
} }
headers = make(map[string]string) headers = make(map[string]string)
if session != "" { if session != "" {
@@ -290,7 +270,7 @@ func (client *RTSP) startStream() {
for { for {
Printf("reconnecting:%s in 5 seconds", client.URL) Printf("reconnecting:%s in 5 seconds", client.URL)
select { select {
case <-client.Context.Done(): case <-client.Done():
client.Stop() client.Stop()
return return
case <-t.C: case <-t.C:
@@ -346,7 +326,7 @@ func (client *RTSP) startStream() {
pack = &RTPPack{ pack = &RTPPack{
Type: RTP_TYPE_AUDIO, Type: RTP_TYPE_AUDIO,
} }
if client.ACodec == "" { if client.ASdp.Codec != "aac" {
continue continue
} }
case client.aRTPControlChannel: case client.aRTPControlChannel:

View File

@@ -23,7 +23,7 @@ var config = struct {
RemoteAddr string RemoteAddr string
Timeout int Timeout int
Reconnect bool Reconnect bool
}{":554", false, "rtsp://localhost/${streamPath}", 0,false} }{":554", false, "rtsp://localhost/${streamPath}", 0, false}
func init() { func init() {
InstallPlugin(&PluginConfig{ InstallPlugin(&PluginConfig{
@@ -131,10 +131,8 @@ type RTSP struct {
SDPMap map[string]*SDPInfo SDPMap map[string]*SDPInfo
nonce string nonce string
closeOld bool closeOld bool
AControl string ASdp *SDPInfo
VControl string VSdp *SDPInfo
ACodec string
VCodec string
aacsent bool aacsent bool
Timeout int Timeout int
//tcp channels //tcp channels

View File

@@ -11,7 +11,7 @@ type SDPInfo struct {
AVType string AVType string
Codec string Codec string
TimeScale int TimeScale int
Control []string Control string
Rtpmap int Rtpmap int
Config []byte Config []byte
SpropParameterSets [][]byte SpropParameterSets [][]byte
@@ -31,17 +31,13 @@ func ParseSDP(sdpRaw string) map[string]*SDPInfo {
switch typeval[0] { switch typeval[0] {
case "m": case "m":
if len(fields) > 0 { if len(fields) > 0 {
switch fields[0] { info = &SDPInfo{AVType: fields[0]}
case "audio", "video": sdpMap[info.AVType] = info
sdpMap[fields[0]] = &SDPInfo{AVType: fields[0]} mfields := strings.Split(fields[1], " ")
info = sdpMap[fields[0]] if len(mfields) >= 3 {
mfields := strings.Split(fields[1], " ") info.PayloadType, _ = strconv.Atoi(mfields[2])
if len(mfields) >= 3 {
info.PayloadType, _ = strconv.Atoi(mfields[2])
}
} }
} }
case "a": case "a":
if info != nil { if info != nil {
for _, field := range fields { for _, field := range fields {
@@ -51,7 +47,7 @@ func ParseSDP(sdpRaw string) map[string]*SDPInfo {
val := keyval[1] val := keyval[1]
switch key { switch key {
case "control": case "control":
info.Control = append(info.Control, val) info.Control = val
case "rtpmap": case "rtpmap":
info.Rtpmap, _ = strconv.Atoi(val) info.Rtpmap, _ = strconv.Atoi(val)
} }
@@ -60,6 +56,10 @@ func ParseSDP(sdpRaw string) map[string]*SDPInfo {
if len(keyval) >= 2 { if len(keyval) >= 2 {
key := keyval[0] key := keyval[0]
switch key { switch key {
case "PCMA":
info.Codec = "pcma"
case "PCMU":
info.Codec = "pcmu"
case "MPEG4-GENERIC": case "MPEG4-GENERIC":
info.Codec = "aac" info.Codec = "aac"
case "H264": case "H264":

View File

@@ -318,19 +318,17 @@ func (session *RTSP) handleRequest(req *Request) {
session.SDPRaw = req.Body session.SDPRaw = req.Body
session.SDPMap = ParseSDP(req.Body) session.SDPMap = ParseSDP(req.Body)
if session.Publish(streamPath) { if session.Publish(streamPath) {
sdp, ok := session.SDPMap["audio"] var ok bool
if ok { if session.ASdp, ok = session.SDPMap["audio"]; ok {
session.AControl = sdp.Control[0] session.WriteASC(session.ASdp.Config)
session.ACodec = sdp.Codec Printf("audio codec[%s]\n", session.ASdp.Codec)
session.WriteASC(sdp.Config)
Printf("audio codec[%s]\n", session.ACodec)
} }
if sdp, ok = session.SDPMap["video"]; ok { if session.VSdp, ok = session.SDPMap["video"]; ok {
session.VControl = sdp.Control[0] if len(session.VSdp.SpropParameterSets) > 1 {
session.VCodec = sdp.Codec session.WriteSPS(session.VSdp.SpropParameterSets[0])
session.WriteSPS(sdp.SpropParameterSets[0]) session.WritePPS(session.VSdp.SpropParameterSets[1])
session.WritePPS(sdp.SpropParameterSets[1]) }
Printf("video codec[%s]\n", session.VCodec) Printf("video codec[%s]\n", session.VSdp.Codec)
} }
session.Stream.Type = "RTSP" session.Stream.Type = "RTSP"
session.RTSPInfo.StreamInfo = &session.Stream.StreamInfo session.RTSPInfo.StreamInfo = &session.Stream.StreamInfo
@@ -379,8 +377,8 @@ func (session *RTSP) handleRequest(req *Request) {
// return // return
//} //}
vPath := "" vPath := ""
if strings.Index(strings.ToLower(session.VControl), "rtsp://") == 0 { if strings.Index(strings.ToLower(session.VSdp.Control), "rtsp://") == 0 {
vControlUrl, err := url.Parse(session.VControl) vControlUrl, err := url.Parse(session.VSdp.Control)
if err != nil { if err != nil {
res.StatusCode = 500 res.StatusCode = 500
res.Status = "Invalid VControl" res.Status = "Invalid VControl"
@@ -391,12 +389,12 @@ func (session *RTSP) handleRequest(req *Request) {
} }
vPath = vControlUrl.String() vPath = vControlUrl.String()
} else { } else {
vPath = session.VControl vPath = session.VSdp.Control
} }
aPath := "" aPath := ""
if strings.Index(strings.ToLower(session.AControl), "rtsp://") == 0 { if strings.Index(strings.ToLower(session.ASdp.Control), "rtsp://") == 0 {
aControlUrl, err := url.Parse(session.AControl) aControlUrl, err := url.Parse(session.ASdp.Control)
if err != nil { if err != nil {
res.StatusCode = 500 res.StatusCode = 500
res.Status = "Invalid AControl" res.Status = "Invalid AControl"
@@ -407,7 +405,7 @@ func (session *RTSP) handleRequest(req *Request) {
} }
aPath = aControlUrl.String() aPath = aControlUrl.String()
} else { } else {
aPath = session.AControl aPath = session.ASdp.Control
} }
mtcp := regexp.MustCompile("interleaved=(\\d+)(-(\\d+))?") mtcp := regexp.MustCompile("interleaved=(\\d+)(-(\\d+))?")