kappanhang/audio.go

147 lines
2.5 KiB
Go
Raw Normal View History

2020-10-20 15:23:12 +02:00
package main
import (
"bytes"
2020-10-20 16:04:35 +02:00
"errors"
"os"
2020-10-20 15:23:12 +02:00
"github.com/akosmarton/papipes"
"github.com/nonoo/kappanhang/log"
)
type audioStruct struct {
source papipes.Source
sink papipes.Sink
// Send to this channel to play audio.
play chan []byte
rec chan []byte
playBuf *bytes.Buffer
canPlay chan bool
}
var audio audioStruct
func (a *audioStruct) playLoop() {
for {
<-a.canPlay
// Trying to read the whole buffer.
d := make([]byte, a.playBuf.Len())
bytesToWrite, err := a.playBuf.Read(d)
if err != nil {
log.Error(err)
continue
}
2020-10-20 16:09:59 +02:00
for {
written, err := a.source.Write(d)
if err != nil {
if _, ok := err.(*os.PathError); !ok {
log.Error(err)
2020-10-20 16:09:59 +02:00
}
return
}
bytesToWrite -= written
if bytesToWrite == 0 {
break
2020-10-20 16:04:35 +02:00
}
d = d[written:]
2020-10-20 16:04:35 +02:00
}
}
}
func (a *audioStruct) recLoop() {
frameBuf := make([]byte, 1920)
buf := bytes.NewBuffer([]byte{})
for {
n, err := a.sink.Read(frameBuf)
if err != nil {
if _, ok := err.(*os.PathError); !ok {
log.Error(err)
}
return
}
buf.Write(frameBuf[:n])
for buf.Len() >= len(frameBuf) {
n, err = buf.Read(frameBuf)
if err != nil {
exit(err)
}
if n != len(frameBuf) {
exit(errors.New("buffer read error"))
}
a.rec <- frameBuf
2020-10-20 15:23:12 +02:00
}
}
}
func (a *audioStruct) loop() {
go a.playLoop()
2020-10-20 16:04:35 +02:00
go a.recLoop()
2020-10-20 15:23:12 +02:00
for {
2020-10-20 16:04:35 +02:00
d := <-a.play
a.playBuf.Write(d)
2020-10-20 15:23:12 +02:00
2020-10-20 16:04:35 +02:00
select {
case a.canPlay <- true:
default:
2020-10-20 15:23:12 +02:00
}
}
}
func (a *audioStruct) init() {
a.source.Name = "kappanhang"
a.source.Filename = "/tmp/kappanhang.source"
a.source.Rate = 48000
a.source.Format = "s16le"
a.source.Channels = 1
2020-10-20 17:10:00 +02:00
a.source.SetProperty("device.buffering.buffer_size", (48000*16)/10) // 100 ms
2020-10-20 15:23:12 +02:00
a.source.SetProperty("device.description", "kappanhang input")
a.sink.Name = "kappanhang"
a.sink.Filename = "/tmp/kappanhang.sink"
a.sink.Rate = 48000
a.sink.Format = "s16le"
a.sink.Channels = 1
2020-10-20 17:10:00 +02:00
a.sink.SetProperty("device.buffering.buffer_size", (48000*16)/10)
2020-10-20 15:23:12 +02:00
a.sink.SetProperty("device.description", "kappanhang output")
if err := a.source.Open(); err != nil {
exit(err)
}
if err := a.sink.Open(); err != nil {
exit(err)
}
a.playBuf = bytes.NewBuffer([]byte{})
a.play = make(chan []byte)
a.canPlay = make(chan bool)
a.rec = make(chan []byte)
go a.loop()
}
func (a *audioStruct) deinit() {
if a.source.IsOpen() {
if err := a.source.Close(); err != nil {
2020-10-20 16:04:35 +02:00
if _, ok := err.(*os.PathError); !ok {
log.Error(err)
}
2020-10-20 15:23:12 +02:00
}
}
if a.sink.IsOpen() {
if err := a.sink.Close(); err != nil {
2020-10-20 16:04:35 +02:00
if _, ok := err.(*os.PathError); !ok {
log.Error(err)
}
2020-10-20 15:23:12 +02:00
}
}
}