From 0550462b4e9f9257528bab70efb10167d59cf176 Mon Sep 17 00:00:00 2001 From: bretello Date: Fri, 23 Oct 2020 22:08:06 +0200 Subject: [PATCH] save audio to mp3 --- broadcast/audio.go | 37 ++++++++++++++++++++++++++++++++++ broadcast/go.mod | 1 + broadcast/go.sum | 2 ++ broadcast/main.go | 50 ++++++++++++++++++++++++++++++---------------- 4 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 broadcast/audio.go diff --git a/broadcast/audio.go b/broadcast/audio.go new file mode 100644 index 0000000..1d100f7 --- /dev/null +++ b/broadcast/audio.go @@ -0,0 +1,37 @@ +package main + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "os" + + lame "github.com/sunicy/go-lame" +) + +func PcmToMp3(audioBuffer *bytes.Buffer, mp3FileName string) { + mp3File, _ := os.OpenFile(mp3FileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) + defer mp3File.Close() + wr, err := lame.NewWriter(mp3File) + if err != nil { + panic("cannot create lame writer, err: " + err.Error()) + + } + wr.InSampleRate = 48000 // input sample rate + wr.InNumChannels = 1 // number of channels: 1 + wr.OutMode = lame.MODE_STEREO // common, 2 channels + wr.OutQuality = 0 // 0: highest; 9: lowest + wr.OutSampleRate = 44100 // output sample rate + io.Copy(wr, audioBuffer) + wr.Close() +} + +func bufWriter(stuff []byte) { + buf := new(bytes.Buffer) + err := binary.Write(buf, binary.LittleEndian, stuff) + if err != nil { + fmt.Println("binary.Write failed:", err) + } + fmt.Printf("% x", buf.Bytes()) +} diff --git a/broadcast/go.mod b/broadcast/go.mod index c4b1241..057b627 100644 --- a/broadcast/go.mod +++ b/broadcast/go.mod @@ -4,5 +4,6 @@ go 1.15 require ( github.com/golang/protobuf v1.4.2 // indirect + github.com/sunicy/go-lame v0.0.0-20200422031049-1c192eaafa39 layeh.com/gumble v0.0.0-20200818122324-146f9205029b ) diff --git a/broadcast/go.sum b/broadcast/go.sum index b13cc2b..c89c663 100644 --- a/broadcast/go.sum +++ b/broadcast/go.sum @@ -12,6 +12,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/sunicy/go-lame v0.0.0-20200422031049-1c192eaafa39 h1:P/6L4pZMkHutxyefALLAiXCPkcD+5NcvJRGayZmtBmY= +github.com/sunicy/go-lame v0.0.0-20200422031049-1c192eaafa39/go.mod h1:H5mJP3sFKpUGaeckgSaMVXcTgnSgImhx54qyQXbpTVY= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/broadcast/main.go b/broadcast/main.go index d39540b..600fd9b 100644 --- a/broadcast/main.go +++ b/broadcast/main.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "os" "time" @@ -17,25 +18,37 @@ import ( ) type AudioListener struct { - name string + buffer *bytes.Buffer } -func (audiolistener AudioListener) OnAudioStream(e *gumble.AudioStreamEvent) { - fmt.Printf("Received AudioStreamEvent from %s\n", e.User.Name) - go ReadPacket(e.C) +func (listener AudioListener) OnAudioStream(e *gumble.AudioStreamEvent) { + // One AudioStreamEvent for person speaking on the channel + // fmt.Printf("Received AudioStreamEvent from %s\n", e.User.Name) // debug + go func(ch <-chan *gumble.AudioPacket) { + outside: + for { + select { + case packet := <-ch: + fmt.Printf(".") + listener.buffer.Write(UnsafeCastInt16sToBytes(packet.AudioBuffer)) + case <-time.After(100 * time.Millisecond): + fmt.Println("timeout") + break outside + } + } + // fmt.Println("\nFinished processing audio packets") // debug + SaveBufToMP3(listener.buffer) + listener.buffer.Reset() + }(e.C) } -func ReadPacket(ch <-chan *gumble.AudioPacket) { - outFile := "pcm_out.raw" - fmt.Printf("Saving out to %s", outFile) // debug - pcm_out, _ := os.OpenFile(outFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) - defer pcm_out.Close() +func SaveBufToMP3(buffer *bytes.Buffer) { + outFileName := "recording.mp3" + fmt.Printf("Saving out to %s", outFileName) // debug + // outFile, _ := os.OpenFile(outFileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) + // defer outFile.Close() - for packet := range ch { - // log.Printf("Message from %s", packet.Sender.Name) // debug - buf := packet.AudioBuffer - pcm_out.Write(UnsafeCastInt16sToBytes(buf)) - } + PcmToMp3(buffer, outFileName) // TODO: check output, err } func main() { @@ -45,12 +58,16 @@ func main() { config.Attach(gumbleutil.Listener{ TextMessage: func(e *gumble.TextMessageEvent) { - fmt.Printf("Received text message: %s\n", e.Message) + log.Printf("Received text message: %s\n", e.Message) + if e.Message == "/quit" { + e.Client.Disconnect() + } }, }) - l := AudioListener{name: "Eventprinter"} + var l AudioListener + l.buffer = new(bytes.Buffer) config.AttachAudio(l) mumbleServer := os.Getenv("MUMBLE_SERVER") if len(mumbleServer) == 0 { @@ -60,7 +77,6 @@ func main() { client, err := gumble.DialWithDialer(&net.Dialer{}, mumbleServer, config, &tls.Config{InsecureSkipVerify: true}) // TODO: fix cert or make it an option if err != nil { panic(err) - } // Print available channels on the server