summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Perry <avaglir@gmail.com>2017-07-28 03:17:55 -0400
committerNathan Perry <avaglir@gmail.com>2017-07-28 03:17:55 -0400
commit381ee40964b21f8a8c4cb9c3f84bd2ddc3290e5c (patch)
treeb4d6bee8a52f09326ea9b576dcf0eef34468b6df
parent2b1b07806bde7206d15ce87b9f05f1176c965b2f (diff)
first pass on wav
-rw-r--r--downloader/downloader.go40
-rw-r--r--downloader/downloader_test.go2
-rw-r--r--thulani.go30
-rw-r--r--wav/wav.go63
-rw-r--r--wav/wav_test.go2
5 files changed, 102 insertions, 35 deletions
diff --git a/downloader/downloader.go b/downloader/downloader.go
index cba9b6a..2b3b2f1 100644
--- a/downloader/downloader.go
+++ b/downloader/downloader.go
@@ -9,7 +9,9 @@ import (
"io/ioutil"
"os"
- "github.com/cryptix/wav"
+ "fmt"
+
+ "github.com/mammothbane/thulani-go/wav"
"github.com/op/go-logging"
)
@@ -30,10 +32,10 @@ func getUrl(inUrl string) (string, error) {
return out, nil
}
-func Download(inUrl string, startTime time.Duration, duration time.Duration) error {
+func Download(inUrl string, startTime time.Duration, duration time.Duration) (<-chan []byte, error) {
targetUrl, err := getUrl(inUrl)
if err != nil {
- return err
+ return nil, err
}
startSecond := int(startTime.Seconds())
@@ -44,7 +46,7 @@ func Download(inUrl string, startTime time.Duration, duration time.Duration) err
"-i", targetUrl,
"-c:a", "pcm_s16le",
"-f", "wav",
- "-ar", "44100",
+ "-ar", "48000",
"-ac", "2",
"-vn", "-y",
}
@@ -53,34 +55,40 @@ func Download(inUrl string, startTime time.Duration, duration time.Duration) err
args = append(args, "-t", strconv.Itoa(dur))
}
- file, err := ioutil.TempFile("", "dl")
+ file, err := ioutil.TempFile("", "thulani_")
if err != nil {
- return err
+ return nil, err
}
- defer func() {
+
+ clearTemp := func() {
if err := os.Remove(file.Name()); err != nil {
log.Errorf("unable to remove temp file: %q", err)
}
- }()
+ }
args = append(args, file.Name())
+ //args = append(args, "out.wav")
+
+ fmt.Println(args)
dl := exec.Command(`ffmpeg`, args...)
b, err := dl.CombinedOutput()
if err != nil {
+ clearTemp()
log.Errorf("ffmpeg failed: \n%v", string(b))
- return err
+ return nil, err
}
- info, err := os.Stat(file.Name())
+ ch, done, err := wav.Load(file.Name())
if err != nil {
- return err
+ clearTemp()
+ return nil, err
}
- _, err = wav.NewReader(file, info.Size())
- if err != nil {
- return err
- }
+ go func() {
+ <-done
+ clearTemp()
+ }()
- return nil
+ return ch, err
}
diff --git a/downloader/downloader_test.go b/downloader/downloader_test.go
index 37a23d4..f38e1d0 100644
--- a/downloader/downloader_test.go
+++ b/downloader/downloader_test.go
@@ -16,7 +16,7 @@ func TestGetUrl(t *testing.T) {
}
func TestDownload(t *testing.T) {
- if err := Download("https://www.youtube.com/watch?v=_K13GJkGvDw", 10*time.Second, 10*time.Second); err != nil {
+ if _, err := Download("https://www.youtube.com/watch?v=_K13GJkGvDw", 10*time.Second, 10*time.Second); err != nil {
t.Fatal(err)
}
}
diff --git a/thulani.go b/thulani.go
index 6dfdb75..1efc67f 100644
--- a/thulani.go
+++ b/thulani.go
@@ -8,7 +8,10 @@ import (
"strings"
"syscall"
+ "time"
+
"github.com/bwmarrin/discordgo"
+ "github.com/mammothbane/thulani-go/downloader"
)
var config *Config
@@ -99,6 +102,33 @@ func onMessage(s *discordgo.Session, m *discordgo.MessageCreate) {
return
}
+ for _, v := range ctx.Guild.Channels {
+ if v.Type == "voice" && v.Name == "General" {
+ conn, err := ctx.ChannelVoiceJoin(ctx.Guild.ID, v.ID, false, false)
+ if err != nil {
+ log.Errorf("unable to join voice channel: %q", err)
+ break
+ }
+
+ ch, err := downloader.Download("https://www.youtube.com/watch?v=_K13GJkGvDw", 10*time.Second, 10*time.Second)
+ if err != nil {
+ log.Errorf("unable to download video")
+ break
+ }
+
+ conn.Speaking(true)
+ go func() {
+ defer conn.Speaking(false)
+
+ for i := range ch {
+ conn.OpusSend <- i
+ }
+ }()
+
+ break
+ }
+ }
+
for _, v := range extraMemes {
v(ctx)
}
diff --git a/wav/wav.go b/wav/wav.go
index 5650a2d..cc155f8 100644
--- a/wav/wav.go
+++ b/wav/wav.go
@@ -5,49 +5,78 @@ package wav
import "C"
import (
"fmt"
+
+ "github.com/op/go-logging"
+ "layeh.com/gopus"
)
-const batchSize = 64
+// number of individual samples per batch (counting all channels)
+const samplesPerBatch = 1920
+
+var log = logging.MustGetLogger("wav")
-func Load(filename string) (<-chan [2]int16, error) {
+func Load(filename string) (<-chan []byte, <-chan struct{}, error) {
cfname := C.CString(filename)
wav := C.drwav_open_file(cfname)
if wav == nil {
- return nil, fmt.Errorf("Unable to initialize drwav.")
+ return nil, nil, fmt.Errorf("Unable to initialize drwav.")
}
if int(wav.channels) != 2 {
C.drwav_close(wav)
- return nil, fmt.Errorf("Wrong number of channels!")
+ return nil, nil, fmt.Errorf("Wrong number of channels!")
}
- if int(wav.sampleRate) != 44100 {
+ if int(wav.sampleRate) != 48000 {
C.drwav_close(wav)
- return nil, fmt.Errorf("Wrong sample rate.")
+ return nil, nil, fmt.Errorf("Wrong sample rate.")
}
- ch := make(chan [2]int16, 1024*32)
+ ch := make(chan []byte, 1024*32)
+ enc, err := gopus.NewEncoder(int(wav.sampleRate), int(wav.channels), gopus.Audio)
+ if err != nil {
+ return nil, nil, err
+ }
+ doneCh := make(chan struct{})
+ encoderCh := make(chan []int16, 2*48000*2)
go func() {
- buf := C.malloc(C.size_t(batchSize * wav.bytesPerSample))
+ buf := C.malloc(C.size_t(samplesPerBatch * wav.bytesPerSample))
defer C.free(buf)
defer C.drwav_close(wav)
- for i := 0; i < int(wav.totalSampleCount)/batchSize; i++ {
- readSamples := C.drwav_read_s16(wav, batchSize, (*C.dr_int16)(buf))
-
+ for i := 0; i < (int(wav.totalSampleCount)/samplesPerBatch)+1; i++ {
+ readSamples := C.drwav_read_s16(wav, samplesPerBatch, (*C.dr_int16)(buf))
slc := (*[1 << 30]int16)(buf)[:readSamples:readSamples]
- for i := 0; i < int(readSamples); i += 2 {
- ch <- [2]int16{slc[i], slc[i+1]}
- }
+ encoderCh <- slc
- if readSamples < batchSize {
+ if readSamples < samplesPerBatch {
break
}
}
- close(ch)
+ close(encoderCh)
}()
- return ch, nil
+ go func(channels int) {
+ elems := []int16{}
+ for v := range encoderCh {
+ elems = append(elems, v...)
+
+ if len(elems) > samplesPerBatch*channels {
+ opus, err := enc.Encode(elems[:samplesPerBatch*channels], samplesPerBatch, samplesPerBatch*channels*2)
+ elems = elems[samplesPerBatch*channels:]
+ if err != nil {
+ log.Errorf("Error encoding opus audio: %q", err)
+ continue
+ }
+ ch <- opus
+ }
+ }
+
+ close(ch)
+ close(doneCh)
+ }(int(wav.channels))
+
+ return ch, doneCh, nil
}
diff --git a/wav/wav_test.go b/wav/wav_test.go
index a641b8f..5d6bef7 100644
--- a/wav/wav_test.go
+++ b/wav/wav_test.go
@@ -8,7 +8,7 @@ import (
func TestLoad(t *testing.T) {
ch, err := Load("../downloader/out.wav")
if err != nil {
- t.Error(err)
+ t.Fatal(err)
}
ct := 0