tgutils/audio.go (view raw)
1// Package tgutils provides extra functions to make certain tasks easier.
2package tgutils
3
4import (
5 "github.com/syfaro/telegram-bot-api"
6 "os"
7 "os/exec"
8 "path/filepath"
9 "strconv"
10 "sync"
11 "time"
12)
13
14var rand uint32
15var randmu sync.Mutex
16
17func reseed() uint32 {
18 return uint32(time.Now().UnixNano() + int64(os.Getpid()))
19}
20
21func nextSuffix() string {
22 randmu.Lock()
23 r := rand
24 if r == 0 {
25 r = reseed()
26 }
27 r = r*1664525 + 1013904223 // constants from Numerical Recipes
28 rand = r
29 randmu.Unlock()
30 return strconv.Itoa(int(1e9 + r%1e9))[1:]
31}
32
33// this function ripped from ioutils.TempFile, except with a suffix, instead of prefix.
34func tempFileWithSuffix(dir, suffix string) (f *os.File, err error) {
35 if dir == "" {
36 dir = os.TempDir()
37 }
38
39 nconflict := 0
40 for i := 0; i < 10000; i++ {
41 name := filepath.Join(dir, nextSuffix()+suffix)
42 f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
43 if os.IsExist(err) {
44 if nconflict++; nconflict > 10 {
45 randmu.Lock()
46 rand = reseed()
47 randmu.Unlock()
48 }
49 continue
50 }
51 break
52 }
53 return
54}
55
56// EncodeAudio takes a file and attempts to convert it to a .ogg for Telegram.
57// It then updates the path to the audio file in the AudioConfig.
58//
59// This function requires ffmpeg and opusenc to be installed on the system!
60func EncodeAudio(audio *tgbotapi.AudioConfig) error {
61 f, err := tempFileWithSuffix(os.TempDir(), "_tgutils.ogg")
62 if err != nil {
63 return err
64 }
65 defer f.Close()
66
67 ffmpegArgs := []string{
68 "-i",
69 audio.FilePath,
70 "-f",
71 "wav",
72 "-",
73 }
74
75 opusArgs := []string{
76 "--bitrate",
77 "256",
78 "-",
79 f.Name(),
80 }
81
82 c1 := exec.Command("ffmpeg", ffmpegArgs...)
83 c2 := exec.Command("opusenc", opusArgs...)
84
85 c2.Stdin, _ = c1.StdoutPipe()
86 c2.Stdout = os.Stdout
87 c2.Start()
88 c1.Run()
89 c2.Wait()
90
91 return nil
92}