main.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "time"
  6. "github.com/bwmarrin/discordgo"
  7. "github.com/pion/rtp"
  8. "github.com/pion/webrtc/v3/pkg/media"
  9. "github.com/pion/webrtc/v3/pkg/media/oggwriter"
  10. )
  11. // Variables used for command line parameters
  12. var (
  13. Token string
  14. ChannelID string
  15. GuildID string
  16. )
  17. func init() {
  18. flag.StringVar(&Token, "t", "", "Bot Token")
  19. flag.StringVar(&GuildID, "g", "", "Guild in which voice channel exists")
  20. flag.StringVar(&ChannelID, "c", "", "Voice channel to connect to")
  21. flag.Parse()
  22. }
  23. func createPionRTPPacket(p *discordgo.Packet) *rtp.Packet {
  24. return &rtp.Packet{
  25. Header: rtp.Header{
  26. Version: 2,
  27. // Taken from Discord voice docs
  28. PayloadType: 0x78,
  29. SequenceNumber: p.Sequence,
  30. Timestamp: p.Timestamp,
  31. SSRC: p.SSRC,
  32. },
  33. Payload: p.Opus,
  34. }
  35. }
  36. func handleVoice(c chan *discordgo.Packet) {
  37. files := make(map[uint32]media.Writer)
  38. for p := range c {
  39. file, ok := files[p.SSRC]
  40. if !ok {
  41. var err error
  42. file, err = oggwriter.New(fmt.Sprintf("%d.ogg", p.SSRC), 48000, 2)
  43. if err != nil {
  44. fmt.Printf("failed to create file %d.ogg, giving up on recording: %v\n", p.SSRC, err)
  45. return
  46. }
  47. files[p.SSRC] = file
  48. }
  49. // Construct pion RTP packet from DiscordGo's type.
  50. rtp := createPionRTPPacket(p)
  51. err := file.WriteRTP(rtp)
  52. if err != nil {
  53. fmt.Printf("failed to write to file %d.ogg, giving up on recording: %v\n", p.SSRC, err)
  54. }
  55. }
  56. // Once we made it here, we're done listening for packets. Close all files
  57. for _, f := range files {
  58. f.Close()
  59. }
  60. }
  61. func main() {
  62. s, err := discordgo.New("Bot " + Token)
  63. if err != nil {
  64. fmt.Println("error creating Discord session:", err)
  65. return
  66. }
  67. defer s.Close()
  68. // We only really care about receiving voice state updates.
  69. s.Identify.Intents = discordgo.IntentsGuildVoiceStates
  70. err = s.Open()
  71. if err != nil {
  72. fmt.Println("error opening connection:", err)
  73. return
  74. }
  75. v, err := s.ChannelVoiceJoin(GuildID, ChannelID, true, false)
  76. if err != nil {
  77. fmt.Println("failed to join voice channel:", err)
  78. return
  79. }
  80. go func() {
  81. time.Sleep(10 * time.Second)
  82. close(v.OpusRecv)
  83. v.Close()
  84. }()
  85. handleVoice(v.OpusRecv)
  86. }