Browse Source

修复webrtc 推流功能

v4
dexter 3 years ago
parent
commit
f479ff8cc4
  1. 95
      main.go
  2. 98
      webrtc/config.go

95
main.go

@ -11,18 +11,22 @@ import (
"time" "time"
"github.com/Monibuca/engine/v3" "github.com/Monibuca/engine/v3"
"github.com/Monibuca/plugin-webrtc/v3/webrtc"
// "github.com/Monibuca/plugin-webrtc/v3/webrtc"
"github.com/Monibuca/utils/v3" "github.com/Monibuca/utils/v3"
"github.com/pion/rtcp" "github.com/pion/rtcp"
. "github.com/pion/webrtc/v3" . "github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/pkg/media" "github.com/pion/webrtc/v3/pkg/media"
) )
var config struct { var config = struct {
ICEServers []string ICEServers []string
PublicIP []string PublicIP []string
PortMin uint16 PortMin uint16
PortMax uint16 PortMax uint16
} PLI time.Duration
}{nil, nil, 0, 0, 2000}
// }{[]string{ // }{[]string{
// "stun:stun.ekiga.net", // "stun:stun.ekiga.net",
@ -88,51 +92,18 @@ type WebRTC struct {
} }
func (rtc *WebRTC) Publish(streamPath string) bool { func (rtc *WebRTC) Publish(streamPath string) bool {
// rtc.m.RegisterCodec(NewRTPCodec(RTPCodecTypeVideo, if _, err := rtc.AddTransceiverFromKind(RTPCodecTypeVideo); err != nil {
// H264,
// 90000,
// 0,
// "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
// DefaultPayloadTypeH264,
// new(codec.H264)))
// rtc.m.RegisterCodec(RTPCodecParameters{
// RTPCodecCapability: RTPCodecCapability{MimeType: "video/h264", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
// PayloadType: 96,
// }, RTPCodecTypeVideo);
//m.RegisterCodec(NewRTPPCMUCodec(DefaultPayloadTypePCMU, 8000))
// if !strings.HasPrefix(rtc.RemoteAddr, "127.0.0.1") && !strings.HasPrefix(rtc.RemoteAddr, "[::1]") {
// rtc.s.SetNAT1To1IPs(config.PublicIP, ICECandidateTypeHost)
// }
peerConnection, err := api.NewPeerConnection(Configuration{
// ICEServers: []ICEServer{
// {
// URLs: config.ICEServers,
// },
// },
})
rtc.PeerConnection = peerConnection
if err != nil { if err != nil {
utils.Println(err) utils.Println(err)
return false return false
} }
if _, err = peerConnection.AddTransceiverFromKind(RTPCodecTypeVideo); err != nil {
if err != nil {
utils.Println(err)
return false
}
}
if err != nil {
return false
} }
stream := &engine.Stream{ stream := &engine.Stream{
Type: "WebRTC", Type: "WebRTC",
StreamPath: streamPath, StreamPath: streamPath,
} }
if stream.Publish() { if stream.Publish() {
peerConnection.OnICEConnectionStateChange(func(connectionState ICEConnectionState) { rtc.OnICEConnectionStateChange(func(connectionState ICEConnectionState) {
utils.Printf("%s Connection State has changed %s ", streamPath, connectionState.String()) utils.Printf("%s Connection State has changed %s ", streamPath, connectionState.String())
switch connectionState { switch connectionState {
case ICEConnectionStateDisconnected, ICEConnectionStateFailed: case ICEConnectionStateDisconnected, ICEConnectionStateFailed:
@ -140,19 +111,8 @@ func (rtc *WebRTC) Publish(streamPath string) bool {
} }
}) })
//f, _ := os.OpenFile("resource/live/rtc.h264", os.O_TRUNC|os.O_WRONLY, 0666) //f, _ := os.OpenFile("resource/live/rtc.h264", os.O_TRUNC|os.O_WRONLY, 0666)
peerConnection.OnTrack(func(track *TrackRemote, receiver *RTPReceiver) { rtc.OnTrack(func(track *TrackRemote, receiver *RTPReceiver) {
defer stream.Close()
go func() {
ticker := time.NewTicker(time.Second * 2)
select {
case <-ticker.C:
if rtcpErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(track.SSRC())}}); rtcpErr != nil {
fmt.Println(rtcpErr)
}
case <-stream.Done():
return
}
}()
if codec := track.Codec(); track.Kind() == RTPCodecTypeAudio { if codec := track.Codec(); track.Kind() == RTPCodecTypeAudio {
var at *engine.RTPAudio var at *engine.RTPAudio
switch codec.MimeType { switch codec.MimeType {
@ -165,15 +125,36 @@ func (rtc *WebRTC) Publish(streamPath string) bool {
default: default:
return return
} }
for {
b := make([]byte, 1460) b := make([]byte, 1460)
for i, _, err := track.Read(b); err == nil; i, _, err = track.Read(b) { if i, _, err := track.Read(b); err == nil {
at.Push(b[:i]) at.Push(b[:i])
} else {
return
}
} }
} else { } else {
go func() {
ticker := time.NewTicker(time.Millisecond * config.PLI)
for {
select {
case <-ticker.C:
if rtcpErr := rtc.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(track.SSRC())}}); rtcpErr != nil {
fmt.Println(rtcpErr)
}
case <-stream.Done():
return
}
}
}()
vt := stream.NewRTPVideo(7) vt := stream.NewRTPVideo(7)
for {
b := make([]byte, 1460) b := make([]byte, 1460)
for i, _, err := track.Read(b); err == nil; i, _, err = track.Read(b) { if i, _, err := track.Read(b); err == nil {
vt.Push(b[:i]) vt.Push(b[:i])
} else {
return
}
} }
} }
@ -191,7 +172,6 @@ func (rtc *WebRTC) GetAnswer() ([]byte, error) {
} }
gatherComplete := GatheringCompletePromise(rtc.PeerConnection) gatherComplete := GatheringCompletePromise(rtc.PeerConnection)
if err := rtc.SetLocalDescription(answer); err != nil { if err := rtc.SetLocalDescription(answer); err != nil {
utils.Println(err)
return nil, err return nil, err
} }
<-gatherComplete <-gatherComplete
@ -212,7 +192,8 @@ func run() {
if config.PortMin > 0 && config.PortMax > 0 { if config.PortMin > 0 && config.PortMax > 0 {
s.SetEphemeralUDPPortRange(config.PortMin, config.PortMax) s.SetEphemeralUDPPortRange(config.PortMin, config.PortMax)
} }
m.RegisterDefaultCodecs() // m.RegisterDefaultCodecs()
webrtc.RegisterCodecs(&m)
api = NewAPI(WithMediaEngine(&m), WithSettingEngine(s)) api = NewAPI(WithMediaEngine(&m), WithSettingEngine(s))
http.HandleFunc("/api/webrtc/play", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/api/webrtc/play", func(w http.ResponseWriter, r *http.Request) {
utils.CORS(w, r) utils.CORS(w, r)
@ -362,6 +343,7 @@ func run() {
}) })
http.HandleFunc("/api/webrtc/publish", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/api/webrtc/publish", func(w http.ResponseWriter, r *http.Request) {
utils.CORS(w, r)
streamPath := r.URL.Query().Get("streamPath") streamPath := r.URL.Query().Get("streamPath")
offer := SessionDescription{} offer := SessionDescription{}
bytes, err := ioutil.ReadAll(r.Body) bytes, err := ioutil.ReadAll(r.Body)
@ -371,6 +353,9 @@ func run() {
return return
} }
rtc := new(WebRTC) rtc := new(WebRTC)
if rtc.PeerConnection, err = api.NewPeerConnection(Configuration{}); err != nil {
return
}
if rtc.Publish(streamPath) { if rtc.Publish(streamPath) {
if err := rtc.SetRemoteDescription(offer); err != nil { if err := rtc.SetRemoteDescription(offer); err != nil {
utils.Println(err) utils.Println(err)
@ -379,7 +364,7 @@ func run() {
if bytes, err = rtc.GetAnswer(); err == nil { if bytes, err = rtc.GetAnswer(); err == nil {
w.Write(bytes) w.Write(bytes)
} else { } else {
utils.Println(err) utils.Println("GetAnswer:", err)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
return return
} }

98
webrtc/config.go

@ -0,0 +1,98 @@
package webrtc
import (
. "github.com/pion/webrtc/v3"
)
func RegisterCodecs(m *MediaEngine) error {
for _, codec := range []RTPCodecParameters{
{
RTPCodecCapability: RTPCodecCapability{MimeTypePCMU, 8000, 0, "", nil},
PayloadType: 0,
},
{
RTPCodecCapability: RTPCodecCapability{MimeTypePCMA, 8000, 0, "", nil},
PayloadType: 8,
},
} {
if err := m.RegisterCodec(codec, RTPCodecTypeAudio); err != nil {
return err
}
}
videoRTCPFeedback := []RTCPFeedback{{"goog-remb", ""}, {"ccm", "fir"}, {"nack", ""}, {"nack", "pli"}}
for _, codec := range []RTPCodecParameters{
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=96", nil},
// PayloadType: 97,
// },
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=98", nil},
// PayloadType: 99,
// },
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=100", nil},
// PayloadType: 101,
// },
{
RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f", videoRTCPFeedback},
PayloadType: 102,
},
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=102", nil},
// PayloadType: 121,
// },
{
RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f", videoRTCPFeedback},
PayloadType: 127,
},
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=127", nil},
// PayloadType: 120,
// },
{
RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", videoRTCPFeedback},
PayloadType: 125,
},
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=125", nil},
// PayloadType: 107,
// },
{
RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f", videoRTCPFeedback},
PayloadType: 108,
},
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=108", nil},
// PayloadType: 109,
// },
{
RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f", videoRTCPFeedback},
PayloadType: 127,
},
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=127", nil},
// PayloadType: 120,
// },
{
RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032", videoRTCPFeedback},
PayloadType: 123,
},
// {
// RTPCodecCapability: RTPCodecCapability{"video/rtx", 90000, 0, "apt=123", nil},
// PayloadType: 118,
// },
} {
if err := m.RegisterCodec(codec, RTPCodecTypeVideo); err != nil {
return err
}
}
return nil
}
Loading…
Cancel
Save