Receive audio with ffmpeg
projetoarduino opened this issue · comments
I'm trying to change the gstreamer-receive example to use ffmpeg, can someone tell me what I'm doing wrong because I don't hear any audio when I run the software
package main
import (
"fmt"
"time"
"os"
"os/exec"
"github.com/pion/rtcp"
"github.com/pion/webrtc/v3"
//gst "gstreamer-sink"
)
func check(err error) {
if err != nil {
panic(err)
}
}
func main() {
// Prepare the configuration
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
}
// Create a new RTCPeerConnection
peerConnection, err := webrtc.NewPeerConnection(config)
if err != nil {
panic(err)
}
// Set a handler for when a new remote track starts, this handler creates a gstreamer pipeline
// for the given codec
peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
// Send a PLI on an interval so that the publisher is pushing a keyframe every rtcpPLIInterval
go func() {
ticker := time.NewTicker(time.Second * 3)
for range ticker.C {
rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(track.SSRC())}})
if rtcpSendErr != nil {
fmt.Println(rtcpSendErr)
}
}
}()
//codecName := strings.Split(track.Codec().RTPCodecCapability.MimeType, "/")[1]
//fmt.Printf("Track has started, of type %d: %s \n", track.PayloadType(), codecName)
//pipeline := gst.CreatePipeline(track.PayloadType(), strings.ToLower(codecName))
//pipeline.Start()
buf := make([]byte, 1400)
chBuff := make(chan []byte, 1400)
go playTrack(chBuff)
for {
i, _, readErr := track.Read(buf)
if readErr != nil {
panic(err)
}
chBuff <- buf[:i]
//pipeline.Push(buf[:i])
//fmt.Printf("%x", buf[:i])
//fmt.Println(track.PayloadType())
}
})
// 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())
})
// Wait for the offer to be pasted
offer := webrtc.SessionDescription{}
Decode(MustReadStdin(), &offer)
// Set the remote SessionDescription
err = peerConnection.SetRemoteDescription(offer)
if err != nil {
panic(err)
}
// Create an answer
answer, err := peerConnection.CreateAnswer(nil)
if err != nil {
panic(err)
}
// Create channel that is blocked until ICE Gathering is complete
gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
// Sets the LocalDescription, and starts our UDP listeners
err = peerConnection.SetLocalDescription(answer)
if err != nil {
panic(err)
}
// Block until ICE Gathering is complete, disabling trickle ICE
// we do this because we only can exchange one signaling message
// in a production application you should exchange ICE Candidates via OnICECandidate
<-gatherComplete
// Output the answer in base64 so we can paste it in browser
fmt.Println(Encode(*peerConnection.LocalDescription()))
// Block forever
select {}
}
func playTrack(ch <-chan []byte){
//cmd := exec.Command("ffmpeg", "-i", "pipe:0", "-f", "alsa", "default")
cmd:= exec.Command("ffmpeg", "-i", "pipe:0", "-c:a", "copy", "-sample_fmt", "s16p", "-ssrc", "1", "-payload_type", "111", "-b", "96k", "-f", "alsa", "default")
cmd.Stderr = os.Stderr // bind log stream to stderr
//cmd.Stdout = resultBuffer // stdout result will be written here
stdin, err := cmd.StdinPipe() // Open stdin pipe
check(err)
err = cmd.Start() // Start a process on another goroutine
check(err)
for {
_, err = stdin.Write(<-ch) // pump audio data to stdin pipe
check(err)
}
err = stdin.Close() // close the stdin, or ffmpeg will wait forever
check(err)
err = cmd.Wait() // wait until ffmpeg finish
check(err)
}
Hey @projetoarduino
Instead of using stdin/stdout I would send RTP over loopback. See rtp-forwarder
If that example doesn't work for you please re-open or reach out via Slack thanks!
Hi @Sean-Der
I would like to thank you for the quick response
I want to use stdin for the sake of practicality in my project, using loopback doesn't seem right
maybe if you could show me a way so i can continue my journey
Transport is hard to do with audio/video over stdin unfortunately. You will have to put audio+video inside a container (webm) but that will add extra complexity.
I have done this a few times and loopback is the best way. It allows you to send multiple streams and is portable. You also aren't ever going to run out of ports. You can listen on anything in 127.0. 0.0 – 127.255.255.255