mirror of
https://github.com/comma-hacks/webrtc.git
synced 2025-10-07 09:00:53 +08:00
139 lines
3.8 KiB
Go
139 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"secureput"
|
|
"strings"
|
|
|
|
"github.com/asticode/go-astiav"
|
|
"github.com/pion/webrtc/v3"
|
|
)
|
|
|
|
var visionTrack *VisionIpcTrack
|
|
|
|
func ReplaceTrack(prefix string, peerConnection *webrtc.PeerConnection) {
|
|
var err error
|
|
if visionTrack != nil {
|
|
visionTrack.Stop()
|
|
}
|
|
visionTrack, err = NewVisionIpcTrack(prefix + "EncodeData")
|
|
if err != nil {
|
|
log.Fatal(fmt.Errorf("main: creating track failed: %w", err))
|
|
}
|
|
// Create a video track
|
|
videoTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264}, "video", "pion")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
rtpSender, err := peerConnection.AddTrack(videoTrack)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
// Later on, we will use rtpSender.ReplaceTrack() for graceful track replacement
|
|
|
|
// Read incoming RTCP packets
|
|
// Before these packets are returned they are processed by interceptors. For things
|
|
// like NACK this needs to be called.
|
|
go func() {
|
|
rtcpBuf := make([]byte, 1500)
|
|
for {
|
|
if _, _, rtcpErr := rtpSender.Read(rtcpBuf); rtcpErr != nil {
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Set the handler for ICE connection state
|
|
// This will notify you when the peer has connected/disconnected
|
|
peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
|
|
fmt.Printf("Connection State has changed %s \n", connectionState.String())
|
|
if connectionState.String() == "disconnected" {
|
|
visionTrack.Stop()
|
|
} else if connectionState == webrtc.ICEConnectionStateFailed {
|
|
visionTrack.Stop()
|
|
if closeErr := peerConnection.Close(); closeErr != nil {
|
|
log.Println(fmt.Errorf("main: peer connection closed due to error: %w", err))
|
|
}
|
|
} else if connectionState.String() == "connected" {
|
|
astiav.SetLogLevel(astiav.LogLevelError)
|
|
astiav.SetLogCallback(func(l astiav.LogLevel, fmt, msg, parent string) {
|
|
log.Printf("ffmpeg log: %s (level: %d)\n", strings.TrimSpace(msg), l)
|
|
})
|
|
go func() {
|
|
encoderParams := EncoderParams{
|
|
Width: visionTrack.Width(),
|
|
Height: visionTrack.Height(),
|
|
TimeBase: visionTrack.TimeBase(),
|
|
AspectRatio: visionTrack.AspectRatio(),
|
|
PixelFormat: visionTrack.PixelFormat(),
|
|
}
|
|
|
|
encoder, err := NewEncoder(encoderParams)
|
|
|
|
if err != nil {
|
|
log.Fatal(fmt.Errorf("main: creating track failed: %w", err))
|
|
return
|
|
}
|
|
defer encoder.Close()
|
|
|
|
go visionTrack.Start()
|
|
defer visionTrack.Stop()
|
|
|
|
for visionTrack != nil {
|
|
var rtpPacket []byte
|
|
for frame := range visionTrack.Frame {
|
|
// Do something with decoded frame
|
|
fmt.Println(frame.Roll)
|
|
// so right now frame is a raw decoded AVFrame
|
|
// https://github.com/FFmpeg/FFmpeg/blob/n5.0/libavutil/frame.h#L317
|
|
avframe := frame.Frame
|
|
|
|
// we need to:
|
|
// 1. transcode to h264 with adaptive bitrate using astiav
|
|
outFrame, err := encoder.Encode(avframe)
|
|
if err != nil {
|
|
log.Println(fmt.Errorf("encode error: %w", err))
|
|
|
|
continue
|
|
}
|
|
|
|
// 2. create an RTP packet with h264 data inside using pion's rtp packetizer
|
|
fmt.Println(len(outFrame.Data()))
|
|
|
|
// 3. write the RTP packet to the videoTrack
|
|
if _, err = videoTrack.Write(rtpPacket); err != nil {
|
|
if errors.Is(err, io.ErrClosedPipe) {
|
|
// The peerConnection has been closed.
|
|
return
|
|
}
|
|
|
|
log.Println(fmt.Errorf("rtp write error: %w", err))
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
})
|
|
}
|
|
|
|
func main() {
|
|
signal := secureput.Create("go-webrtc-body")
|
|
signal.DeviceMetadata = map[string]interface{}{"isRobot": true}
|
|
signal.Gui = &Face{app: &signal}
|
|
go signal.RunDaemonMode()
|
|
if !signal.Paired() {
|
|
go signal.Gui.Show()
|
|
log.Println("Waiting to pair.")
|
|
<-signal.PairWaitChannel
|
|
}
|
|
signal.OnPeerConnectionCreated = func(pc *webrtc.PeerConnection) {
|
|
ReplaceTrack("road", pc)
|
|
}
|
|
for {
|
|
select {}
|
|
}
|
|
}
|