bwmarrin / discordgo

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

Cannot play steam from You Tube Audio #1582

Open algnot opened 1 month ago

algnot commented 1 month ago

I want to use github.com/kkdai/youtube/v2 and github.com/bwmarrin/discordgo to play youtube audio in my channel I write this code I debug and found that video, err := client.GetVideo(url) and stream, _, err := client.GetStream(video, &formats[0]) are returning correctly, but the audio coming out of my script sounds weird. Can anyone help me?

package bot

import (
    "bufio"
    "fmt"
    "github.com/bwmarrin/discordgo"
    "github.com/kkdai/youtube/v2"
    "io"
    "log"
    "os/exec"
    "time"
)

func playYouTubeAudio(vc *discordgo.VoiceConnection, url string) error {
    client := youtube.Client{}

    video, err := client.GetVideo(url)
    if err != nil {
        return fmt.Errorf("error getting video info: %v", err)
    }

    formats := video.Formats.WithAudioChannels()
    if len(formats) == 0 {
        return fmt.Errorf("no audio formats available for video")
    }

    stream, _, err := client.GetStream(video, &formats[0])
    if err != nil {
        return fmt.Errorf("error getting stream: %v", err)
    }
    defer stream.Close()

    cmd := exec.Command("ffmpeg", "-i", "pipe:0", "-f", "opus", "-ar", "48000", "-ac", "2", "pipe:1")

    ffmpegIn, err := cmd.StdinPipe()
    if err != nil {
        return fmt.Errorf("error creating stdin pipe: %v", err)
    }

    ffmpegOut, err := cmd.StdoutPipe()
    if err != nil {
        return fmt.Errorf("error creating stdout pipe: %v", err)
    }

    ffmpegErr, err := cmd.StderrPipe()
    if err != nil {
        return fmt.Errorf("error creating stderr pipe: %v", err)
    }

    go func() {
        scanner := bufio.NewScanner(ffmpegErr)
        for scanner.Scan() {
            log.Println("FFmpeg: ", scanner.Text())
        }
    }()

    if err := cmd.Start(); err != nil {
        return fmt.Errorf("error starting ffmpeg: %v", err)
    }

    go func() {
        defer func(ffmpegIn io.WriteCloser) {
            err := ffmpegIn.Close()
            if err != nil {
                log.Printf("error closing ffmpeg stream: %v", err)
            }
        }(ffmpegIn)

        _, err := io.Copy(ffmpegIn, stream)
        if err != nil {
            log.Printf("error copying stream to ffmpeg: %v", err)
        }
    }()

    err = vc.Speaking(true)
    if err != nil {
        return err
    }
    defer func(vc *discordgo.VoiceConnection, b bool) {
        err := vc.Speaking(b)
        if err != nil {
            log.Printf("error speaking: %v", err)
        }
    }(vc, false)

    err = playAudioStream(vc, ffmpegOut)
    if err != nil {
        return fmt.Errorf("error playing audio stream: %v", err)
    }

    if err := cmd.Wait(); err != nil {
        return fmt.Errorf("ffmpeg exited with error: %v", err)
    }

    return nil
}

func playAudioStream(vc *discordgo.VoiceConnection, stream io.Reader) error {
    buffer := make([]byte, 960*2*2)

    for {
        n, err := stream.Read(buffer)
        if err != nil && err != io.EOF {
            return fmt.Errorf("error reading audio stream: %v", err)
        }
        if n == 0 {
            break
        }

        vc.OpusSend <- buffer[:n]
        time.Sleep(20 * time.Millisecond)
    }

    return nil
}

This is log in console

Bot is now running
2024/10/13 16:14:11 FFmpeg:  ffmpeg version 7.1 Copyright (c) 2000-2024 the FFmpeg developers
2024/10/13 16:14:11 FFmpeg:    built with Apple clang version 16.0.0 (clang-1600.0.26.3)
2024/10/13 16:14:11 FFmpeg:    configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
2024/10/13 16:14:11 FFmpeg:    libavutil      59. 39.100 / 59. 39.100
2024/10/13 16:14:11 FFmpeg:    libavcodec     61. 19.100 / 61. 19.100
2024/10/13 16:14:11 FFmpeg:    libavformat    61.  7.100 / 61.  7.100
2024/10/13 16:14:11 FFmpeg:    libavdevice    61.  3.100 / 61.  3.100
2024/10/13 16:14:11 FFmpeg:    libavfilter    10.  4.100 / 10.  4.100
2024/10/13 16:14:11 FFmpeg:    libswscale      8.  3.100 /  8.  3.100
2024/10/13 16:14:11 FFmpeg:    libswresample   5.  3.100 /  5.  3.100
2024/10/13 16:14:11 FFmpeg:    libpostproc    58.  3.100 / 58.  3.100
2024/10/13 16:14:12 FFmpeg:  Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'pipe:0':
2024/10/13 16:14:12 FFmpeg:    Metadata:
2024/10/13 16:14:12 FFmpeg:      major_brand     : mp42
2024/10/13 16:14:12 FFmpeg:      minor_version   : 0
2024/10/13 16:14:12 FFmpeg:      compatible_brands: isommp42
2024/10/13 16:14:12 FFmpeg:      encoder         : Google
2024/10/13 16:14:12 FFmpeg:    Duration: 00:04:56.10, start: 0.000000, bitrate: N/A
2024/10/13 16:14:12 FFmpeg:    Stream #0:0[0x1](und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 640x360 [SAR 1:1 DAR 16:9], 263 kb/s, 25 fps, 25 tbr, 12800 tbn (default)
2024/10/13 16:14:12 FFmpeg:        Metadata:
2024/10/13 16:14:12 FFmpeg:          handler_name    : ISO Media file produced by Google Inc.
2024/10/13 16:14:12 FFmpeg:          vendor_id       : [0][0][0][0]
2024/10/13 16:14:12 FFmpeg:    Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 95 kb/s (default)
2024/10/13 16:14:12 FFmpeg:        Metadata:
2024/10/13 16:14:12 FFmpeg:          handler_name    : ISO Media file produced by Google Inc.
2024/10/13 16:14:12 FFmpeg:          vendor_id       : [0][0][0][0]
2024/10/13 16:14:12 FFmpeg:  Stream mapping:
2024/10/13 16:14:12 FFmpeg:    Stream #0:1 -> #0:0 (aac (native) -> opus (libopus))
2024/10/13 16:14:12 FFmpeg:  [libopus @ 0x12de04930] No bit rate set. Defaulting to 96000 bps.
2024/10/13 16:14:12 FFmpeg:  Output #0, opus, to 'pipe:1':
2024/10/13 16:14:12 FFmpeg:    Metadata:
2024/10/13 16:14:12 FFmpeg:      major_brand     : mp42
2024/10/13 16:14:12 FFmpeg:      minor_version   : 0
2024/10/13 16:14:12 FFmpeg:      compatible_brands: isommp42
2024/10/13 16:14:12 FFmpeg:      encoder         : Lavf61.7.100
2024/10/13 16:14:12 FFmpeg:    Stream #0:0(eng): Audio: opus, 48000 Hz, stereo, flt, 96 kb/s (default)
2024/10/13 16:14:12 FFmpeg:        Metadata:
2024/10/13 16:14:12 FFmpeg:          handler_name    : ISO Media file produced by Google Inc.
2024/10/13 16:14:12 FFmpeg:          vendor_id       : [0][0][0][0]
2024/10/13 16:14:12 FFmpeg:          encoder         : Lavc61.19.100 libopus
2024/10/13 16:14:12 FFmpeg:          major_brand     : mp42
2024/10/13 16:14:12 FFmpeg:          minor_version   : 0
2024/10/13 16:14:12 FFmpeg:          compatible_brands: isommp42