mirror of
https://github.com/Monibuca/plugin-webrtc.git
synced 2025-10-05 06:46:57 +08:00
修复webrtc 推流功能
This commit is contained in:
103
main.go
103
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 {
|
|
||||||
utils.Println(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if _, err = peerConnection.AddTransceiverFromKind(RTPCodecTypeVideo); err != nil {
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Println(err)
|
utils.Println(err)
|
||||||
return false
|
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
|
||||||
}
|
}
|
||||||
b := make([]byte, 1460)
|
for {
|
||||||
for i, _, err := track.Read(b); err == nil; i, _, err = track.Read(b) {
|
b := make([]byte, 1460)
|
||||||
at.Push(b[:i])
|
if i, _, err := track.Read(b); err == nil {
|
||||||
|
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)
|
||||||
b := make([]byte, 1460)
|
for {
|
||||||
for i, _, err := track.Read(b); err == nil; i, _, err = track.Read(b) {
|
b := make([]byte, 1460)
|
||||||
vt.Push(b[:i])
|
if i, _, err := track.Read(b); err == nil {
|
||||||
|
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
Normal file
98
webrtc/config.go
Normal file
@@ -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
|
||||||
|
}
|
Reference in New Issue
Block a user