bwmarrin / discordgo

(Golang) Go bindings for Discord
BSD 3-Clause "New" or "Revised" License
5.05k stars 802 forks source link

How do I pipe the output of *discordgo.Packet to ffmpeg? #1546

Open ThallesP opened 2 months ago

ThallesP commented 2 months ago

I'm trying to convert discord's opus packets to .wav using ffmpeg but I can't get it to work with discordgo. I'm a newbie to encoders so i'm probably missing something stupid. Here's my code so far:

package main

import (
    "fmt"
    "os"
    "os/exec"
    "os/signal"
    "syscall"
    "time"

    "github.com/bwmarrin/discordgo"
)

const CHANNEL_ID = "838536675240050708"
const GUILD_ID = "838505728976748624"

func main() {
    dg, err := discordgo.New("Bot " + os.Getenv("BOT_TOKEN"))

    if err != nil {
        panic(err)
    }

    err = dg.Open()

    if err != nil {
        panic(err)
    }

    dgv, err := dg.ChannelVoiceJoin(GUILD_ID, CHANNEL_ID, false, false)

    if err != nil {
        panic(err)
    }

    SaveReceivedAudio(dgv)

    fmt.Println("Bot is now running.  Press CTRL-C to exit.")
    sc := make(chan os.Signal, 1)
    signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
    <-sc

    dg.Close()
}

func SaveReceivedAudio(v *discordgo.VoiceConnection) {
    go func(v *discordgo.VoiceConnection) {
        cmd := exec.Command("/usr/bin/ffmpeg",
            "-ac", "2",
            "-ar", "48000",
            "-f", "s16le",
            "-acodec", "libopus",
            "-i", "-", // take stdin as input
            "/home/thalles/scribe/output.opus",
        )

        cmd.Stderr = os.Stdout

        pipe, err := cmd.StdinPipe()

        if err != nil {
            panic(err)
        }

        err = cmd.Start()

        if err != nil {
            panic(err)
        }

        for {
            select {
            case packet := <-v.OpusRecv:
                /*pkrtp := &rtp.Packet{
                    Header: rtp.Header{
                        Version:        2,
                        PayloadType:    0x78,
                        SequenceNumber: packet.Sequence,
                        Timestamp:      packet.Timestamp,
                        SSRC:           packet.SSRC,
                    },
                    Payload: packet.Opus,
                }
                //pkrtp.MarshalTo(bufferRTP)
                b, _ := pkrtp.Marshal()*/

                pipe.Write(packet.Opus)
                continue
            case <-time.Tick(10 * time.Second):
                pipe.Close()
                fmt.Println("stopping", cmd.Process.Signal(os.Interrupt))
                return
            }

        }
    }(v)
}

I've seen the use of oggwriter but I'm scared that it'll cause overhead