mirror of https://bitbucket.org/ausocean/av.git
mend
This commit is contained in:
parent
94d1f1a156
commit
d66172915e
|
@ -282,7 +282,7 @@ func (ac *audioClient) open() error {
|
|||
// to fix this 8000 and 16000 must be removed from this slice.
|
||||
rates := [8]int{8000, 16000, 32000, 44100, 48000, 88200, 96000, 192000}
|
||||
foundRate := false
|
||||
for r := range rates {
|
||||
for _, r := range rates {
|
||||
if r < ac.rate {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package alsa
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -97,6 +98,7 @@ type Config struct {
|
|||
BitDepth uint
|
||||
RecPeriod float64
|
||||
Codec string
|
||||
Title string
|
||||
}
|
||||
|
||||
// New initializes and returns an ALSA device which has its logger set as the given logger.
|
||||
|
@ -133,12 +135,14 @@ func (d *ALSA) Setup(c config.Config) error {
|
|||
errs = append(errs, errInvalidCodec)
|
||||
c.InputCodec = defaultCodec
|
||||
}
|
||||
|
||||
d.Config = Config{
|
||||
SampleRate: c.SampleRate,
|
||||
Channels: c.Channels,
|
||||
BitDepth: c.BitDepth,
|
||||
RecPeriod: c.RecPeriod,
|
||||
Codec: c.InputCodec,
|
||||
Title: c.AlsaTitle,
|
||||
}
|
||||
|
||||
// Open the requested audio device.
|
||||
|
@ -224,6 +228,8 @@ func (d *ALSA) open() error {
|
|||
d.l.Debug("closing device", "title", d.title)
|
||||
d.dev.Close()
|
||||
d.dev = nil
|
||||
} else {
|
||||
d.title = d.Config.Title
|
||||
}
|
||||
|
||||
// Open sound card and open recording device.
|
||||
|
@ -281,7 +287,7 @@ func (d *ALSA) open() error {
|
|||
|
||||
var rate int
|
||||
foundRate := false
|
||||
for r := range rates {
|
||||
for _, r := range rates {
|
||||
if r < int(d.SampleRate) {
|
||||
continue
|
||||
}
|
||||
|
@ -336,9 +342,13 @@ func (d *ALSA) open() error {
|
|||
bytesPerSecond := rate * channels * (bitdepth / 8)
|
||||
wantPeriodSize := int(float64(bytesPerSecond) * wantPeriod)
|
||||
nearWantPeriodSize := nearestPowerOfTwo(wantPeriodSize)
|
||||
periodSize, err := d.dev.NegotiatePeriodSize(nearWantPeriodSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// At least two period sizes should fit within the buffer.
|
||||
bufSize, err := d.dev.NegotiateBufferSize(nearWantPeriodSize * 2)
|
||||
bufSize, err := d.dev.NegotiateBufferSize(periodSize * 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -355,56 +365,15 @@ func (d *ALSA) open() error {
|
|||
// input continously records audio and writes it to the ringbuffer.
|
||||
// Re-opens the device and tries again if the ASLA device returns an error.
|
||||
func (d *ALSA) input() {
|
||||
for {
|
||||
// Check mode.
|
||||
d.mu.Lock()
|
||||
mode := d.mode
|
||||
d.mu.Unlock()
|
||||
switch mode {
|
||||
case paused:
|
||||
time.Sleep(time.Duration(d.RecPeriod) * time.Second)
|
||||
continue
|
||||
case stopped:
|
||||
if d.dev != nil {
|
||||
d.l.Debug("closing ALSA device", "title", d.title)
|
||||
d.dev.Close()
|
||||
d.dev = nil
|
||||
}
|
||||
err := d.buf.Close()
|
||||
if err != nil {
|
||||
d.l.Error("unable to close pool buffer", "error", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
// Get context and assign cancel function.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
// Read from audio device.
|
||||
d.l.Debug("recording audio for period", "seconds", d.RecPeriod)
|
||||
err := d.dev.Read(d.pb.Data)
|
||||
if err != nil {
|
||||
d.l.Debug("read failed", "error", err.Error())
|
||||
err = d.open() // re-open
|
||||
if err != nil {
|
||||
d.l.Fatal("reopening device failed", "error", err.Error())
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Check device mode.
|
||||
go checkMode(d, cancel)
|
||||
|
||||
// Process audio.
|
||||
d.l.Debug("processing audio")
|
||||
toWrite := d.formatBuffer()
|
||||
// Read from audio device.
|
||||
go tickerRead(d, ctx)
|
||||
|
||||
// Write audio to ringbuffer.
|
||||
n, err := d.buf.Write(toWrite.Data)
|
||||
switch err {
|
||||
case nil:
|
||||
d.l.Debug("wrote audio to ringbuffer", "length", n)
|
||||
case pool.ErrDropped:
|
||||
d.l.Warning("old audio data overwritten")
|
||||
default:
|
||||
d.l.Error("unexpected ringbuffer error", "error", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads from the ringbuffer, returning the number of bytes read upon success.
|
||||
|
@ -443,6 +412,77 @@ func (d *ALSA) Read(p []byte) (int, error) {
|
|||
return n, nil
|
||||
}
|
||||
|
||||
// checkMode is intended to run as a goroutine to call a cancel function on the context
|
||||
// once the mode has changed from normal to stopped.
|
||||
func checkMode(d *ALSA, cancel func()) {
|
||||
d.l.Debug("starting checkMode loop")
|
||||
ticker := time.NewTicker(time.Duration(d.RecPeriod) * time.Second)
|
||||
for range ticker.C {
|
||||
// Check mode.
|
||||
d.mu.Lock()
|
||||
mode := d.mode
|
||||
d.mu.Unlock()
|
||||
switch mode {
|
||||
case paused:
|
||||
time.Sleep(time.Duration(d.RecPeriod) * time.Second)
|
||||
continue
|
||||
case stopped:
|
||||
cancel()
|
||||
if d.dev != nil {
|
||||
d.l.Debug("closing ALSA device", "title", d.title)
|
||||
d.dev.Close()
|
||||
d.dev = nil
|
||||
}
|
||||
err := d.buf.Close()
|
||||
if err != nil {
|
||||
d.l.Error("unable to close pool buffer", "error", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tickerRead uses a timer.ticker to call Read on the device at precise intervals to ensure that reads are
|
||||
// happening at the right time.
|
||||
func tickerRead(d *ALSA, ctx context.Context) {
|
||||
d.l.Debug("starting ticker read loop")
|
||||
ticker := time.NewTicker(time.Duration(d.RecPeriod)*time.Second - time.Duration(30*time.Millisecond))
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
d.l.Debug("context cancelled")
|
||||
return
|
||||
case <-ticker.C:
|
||||
d.l.Debug("recording audio for period", "seconds", d.RecPeriod)
|
||||
err := d.dev.Read(d.pb.Data)
|
||||
if err != nil {
|
||||
d.l.Debug("read failed", "error", err.Error())
|
||||
err = d.open() // re-open
|
||||
if err != nil {
|
||||
d.l.Fatal("reopening device failed", "error", err.Error())
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Process audio.
|
||||
d.l.Debug("processing audio")
|
||||
toWrite := d.formatBuffer()
|
||||
|
||||
// Write audio to ringbuffer.
|
||||
n, err := d.buf.Write(toWrite.Data)
|
||||
switch err {
|
||||
case nil:
|
||||
d.l.Debug("wrote audio to ringbuffer", "length", n)
|
||||
case pool.ErrDropped:
|
||||
d.l.Warning("old audio data overwritten")
|
||||
default:
|
||||
d.l.Error("unexpected ringbuffer error", "error", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// formatBuffer returns audio that has been converted to the desired format.
|
||||
func (d *ALSA) formatBuffer() pcm.Buffer {
|
||||
var err error
|
||||
|
|
BIN
exp/i2s/i2s
BIN
exp/i2s/i2s
Binary file not shown.
|
@ -1,33 +1,8 @@
|
|||
2024/03/04 16:27:36 recording device is: ALC892 Analog
|
||||
2024/03/04 16:27:36 Number of channels is: 2
|
||||
2024/03/04 16:27:36 rate is: 44100
|
||||
2024/03/04 16:27:36 buffer size is: 1024
|
||||
2024/03/04 16:27:36 bytes per frame: 8
|
||||
2024/03/04 16:27:36 device state: PREPARED
|
||||
2024/03/04 16:27:36 2 channels, 44100 hz, S16_LE
|
||||
2024/03/04 16:27:36 prepared and ready to record
|
||||
2024/03/04 16:27:44 read error: ioctl read (24 bytes) 0x4151 failed: broken pipe
|
||||
2024/03/04 16:27:44 trying to restart device
|
||||
2024/03/04 16:27:44 device state: XRUN
|
||||
2024/03/04 16:27:44 device state: PREPARED
|
||||
2024/03/04 16:27:44 restart successful
|
||||
2024/03/04 16:27:47 read error: ioctl read (24 bytes) 0x4151 failed: broken pipe
|
||||
2024/03/04 16:27:47 trying to restart device
|
||||
2024/03/04 16:27:47 device state: XRUN
|
||||
2024/03/04 16:27:47 device state: PREPARED
|
||||
2024/03/04 16:27:47 restart successful
|
||||
2024/03/04 16:27:49 read error: ioctl read (24 bytes) 0x4151 failed: broken pipe
|
||||
2024/03/04 16:27:49 trying to restart device
|
||||
2024/03/04 16:27:49 device state: XRUN
|
||||
2024/03/04 16:27:49 device state: PREPARED
|
||||
2024/03/04 16:27:49 restart successful
|
||||
2024/03/04 16:27:52 read error: ioctl read (24 bytes) 0x4151 failed: broken pipe
|
||||
2024/03/04 16:27:52 trying to restart device
|
||||
2024/03/04 16:27:52 device state: XRUN
|
||||
2024/03/04 16:27:52 device state: PREPARED
|
||||
2024/03/04 16:27:52 restart successful
|
||||
2024/03/04 16:27:55 read error: ioctl read (24 bytes) 0x4151 failed: broken pipe
|
||||
2024/03/04 16:27:55 trying to restart device
|
||||
2024/03/04 16:27:55 device state: XRUN
|
||||
2024/03/04 16:27:55 device state: PREPARED
|
||||
2024/03/04 16:27:55 restart successful
|
||||
{"level":"debug","time":"2024-03-25T16:18:23.128+1030","caller":"i2s/main.go:41","message":"setting up new device"}
|
||||
{"level":"debug","time":"2024-03-25T16:18:23.128+1030","caller":"alsa/alsa.go:235","message":"opening sound card"}
|
||||
{"level":"debug","time":"2024-03-25T16:18:23.128+1030","caller":"alsa/alsa.go:242","message":"finding audio device"}
|
||||
{"level":"debug","time":"2024-03-25T16:18:23.128+1030","caller":"alsa/alsa.go:262","message":"opening ALSA device","title":"USB Audio"}
|
||||
{"level":"debug","time":"2024-03-25T16:18:23.128+1030","caller":"i2s/main.go:44","message":"failed to setup device","err":"failed to open device: device is unable to record with requested number of channels: Channel count negotiation failure: Requested value 2 is not supported by hardware: Must be 1"}
|
||||
{"level":"debug","time":"2024-03-25T16:18:23.128+1030","caller":"i2s/main.go:55","message":"starting device"}
|
||||
{"level":"debug","time":"2024-03-25T16:18:23.128+1030","caller":"i2s/main.go:58","message":"could not start device","err":"invalid mode: 0"}
|
||||
{"level":"debug","time":"2024-03-25T16:18:23.128+1030","caller":"alsa/alsa.go:381","message":"alsa: getting next chunk ready"}
|
||||
|
|
287
exp/i2s/main.go
287
exp/i2s/main.go
|
@ -1,268 +1,79 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/ausocean/utils/ring"
|
||||
yalsa "github.com/yobert/alsa"
|
||||
"bitbucket.org/ausocean/av/codec/codecutil"
|
||||
"bitbucket.org/ausocean/av/device/alsa"
|
||||
"bitbucket.org/ausocean/av/revid/config"
|
||||
"bitbucket.org/ausocean/utils/logging"
|
||||
)
|
||||
|
||||
const i2sDevName = "simple-card_codec_link snd-soc-dummy-dai-0"
|
||||
|
||||
// type CircBuffer struct {
|
||||
// Buf []byte
|
||||
// Head, Tail int
|
||||
// mu sync.Mutex
|
||||
// }
|
||||
|
||||
// func (c *CircBuffer) nextWrite() {
|
||||
// c.Head++
|
||||
// if c.Head == len(c.Buf) {
|
||||
// c.Head = 0
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (c *CircBuffer) nextRead() {
|
||||
// c.Tail++
|
||||
// if c.Tail == len(c.Buf)-1 {
|
||||
// c.Tail = 0
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (c *CircBuffer) Write(p []byte) {
|
||||
// for i := 0; i < len(p); i++ {
|
||||
// c.mu.Lock()
|
||||
// c.Buf[c.Head] = p[i]
|
||||
// c.nextWrite()
|
||||
// c.mu.Unlock()
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (c *CircBuffer) Read(p []byte) (int, error) {
|
||||
// var diff int
|
||||
// if c.Head > c.Tail {
|
||||
// diff = c.Head - c.Tail
|
||||
// } else {
|
||||
// diff = c.Head - c.Tail + len(c.Buf)
|
||||
// }
|
||||
// if diff > len(p) {
|
||||
// diff = len(p)
|
||||
// }
|
||||
// for i := 0; i < diff; i++ {
|
||||
// c.mu.Lock()
|
||||
// p[i] = c.Buf[c.Tail]
|
||||
// c.nextRead()
|
||||
// c.mu.Unlock()
|
||||
// }
|
||||
// return diff + 1, nil
|
||||
// }
|
||||
|
||||
func main() {
|
||||
logger := log.Default()
|
||||
// Setup logging
|
||||
logFile, err := os.Create("i2s.log")
|
||||
if err != nil {
|
||||
log.Println("failed to create log file:", err)
|
||||
log.Println("couldnt open log file:", err)
|
||||
}
|
||||
l := logging.New(logging.Debug, logFile, false)
|
||||
|
||||
// Set minimum fields required in config.
|
||||
c := config.Config{
|
||||
BitDepth: 16,
|
||||
Channels: 2,
|
||||
SampleRate: 48000,
|
||||
RecPeriod: 1,
|
||||
InputCodec: codecutil.PCM,
|
||||
AlsaTitle: "USB Audio",
|
||||
}
|
||||
|
||||
// Set file to write audio to.
|
||||
output, err := os.Create("output.pcm")
|
||||
if err != nil {
|
||||
l.Error("could not create audio file", "error", err)
|
||||
return
|
||||
}
|
||||
logger.SetOutput(logFile)
|
||||
|
||||
// Set capture type.
|
||||
var i2s bool = false
|
||||
|
||||
// Find devices.
|
||||
cards, err := yalsa.OpenCards()
|
||||
if err != nil {
|
||||
log.Println("failed to open cards:", err)
|
||||
}
|
||||
|
||||
var allDevices []*yalsa.Device
|
||||
for _, card := range cards {
|
||||
devices, err := card.Devices()
|
||||
if err != nil {
|
||||
log.Println("could not get Devices:", err)
|
||||
}
|
||||
allDevices = append(allDevices, devices...)
|
||||
}
|
||||
|
||||
var dev *yalsa.Device
|
||||
if i2s {
|
||||
// For I2S we know the name of the device, so select that card.
|
||||
for _, device := range allDevices {
|
||||
if device.Title == i2sDevName {
|
||||
dev = device
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise, use the first recording device we find.
|
||||
for _, card := range cards {
|
||||
devices, err := card.Devices()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
for _, device := range devices {
|
||||
if device.Type != yalsa.PCM {
|
||||
continue
|
||||
}
|
||||
if device.Record && dev == nil {
|
||||
dev = device
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dev == nil {
|
||||
log.Println("No recording device found")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("recording device is:", dev.Title)
|
||||
|
||||
// Setup device.
|
||||
err = dev.Open()
|
||||
d := alsa.New(l)
|
||||
|
||||
l.Debug("setting up new device")
|
||||
err = d.Setup(c)
|
||||
if err != nil {
|
||||
log.Println("open failed:", err)
|
||||
return
|
||||
l.Debug("failed to setup device", "err", err)
|
||||
}
|
||||
defer dev.Close()
|
||||
|
||||
channels, err := dev.NegotiateChannels(2)
|
||||
// Create a new lexer to read from the device buffer.
|
||||
// lexer, err := codecutil.NewByteLexer(d.DataSize())
|
||||
// if err != nil {
|
||||
// l.Error("could not make new lexer", "error", err)
|
||||
// return
|
||||
// }
|
||||
|
||||
// Start recording from device.
|
||||
l.Debug("starting device")
|
||||
err = d.Start()
|
||||
if err != nil {
|
||||
log.Println("failed to negotiate channels:", err)
|
||||
return
|
||||
}
|
||||
log.Println("Number of channels is:", channels)
|
||||
|
||||
rate, err := dev.NegotiateRate(44100)
|
||||
if err != nil {
|
||||
log.Println("rate negotiation failed:", rate)
|
||||
return
|
||||
}
|
||||
log.Println("rate is:", rate)
|
||||
|
||||
bufferSize, err := dev.NegotiateBufferSize(1024)
|
||||
if err != nil {
|
||||
log.Println("buffer size negotiation failed", err)
|
||||
return
|
||||
}
|
||||
log.Println("buffer size is:", bufferSize)
|
||||
log.Println("bytes per frame:", dev.BytesPerFrame())
|
||||
|
||||
// circ := &CircBuffer{Buf: make([]byte, bufferSize*dev.BytesPerFrame()*4), Head: 0, Tail: 0}
|
||||
rBuf := ring.NewBuffer(8, 16*bufferSize*dev.BytesPerFrame(), 2*time.Second)
|
||||
|
||||
err = prepare(dev, false)
|
||||
if err != nil {
|
||||
log.Println("Prepare failed:", err)
|
||||
return
|
||||
l.Debug("could not start device", "err", err)
|
||||
}
|
||||
|
||||
log.Println(dev.BufferFormat())
|
||||
log.Println("prepared and ready to record")
|
||||
|
||||
// Record audio.
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(1)
|
||||
go recordAudio(wg, rBuf, bufferSize, dev)
|
||||
|
||||
// Write audio to file.
|
||||
file, err := os.Create("test.pcm")
|
||||
if err != nil {
|
||||
log.Println("couldn't create file:", err)
|
||||
return
|
||||
}
|
||||
go writeAudio(wg, file, rBuf, bufferSize)
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func prepare(dev *yalsa.Device, restart bool) error {
|
||||
if restart {
|
||||
getDeviceStatus(dev)
|
||||
dev.Close()
|
||||
err := dev.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err := dev.Prepare()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
getDeviceStatus(dev)
|
||||
return nil
|
||||
}
|
||||
|
||||
func recordAudio(wg *sync.WaitGroup, buf *ring.Buffer, size int, dev *yalsa.Device) {
|
||||
// Create a buffer for single read.
|
||||
p := make([]byte, size*dev.BytesPerFrame())
|
||||
var err error
|
||||
// Start lexing to output file.
|
||||
// lexer.Lex(output, d, 1)
|
||||
buf := make([]byte, 4*48000)
|
||||
for {
|
||||
err = dev.Read(p)
|
||||
n, err := d.Read(buf)
|
||||
if err != nil {
|
||||
log.Println("read error:", err)
|
||||
log.Println("trying to restart device")
|
||||
err = prepare(dev, true)
|
||||
if err != nil {
|
||||
log.Println("failed to restart device:", err)
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
log.Println("restart successful")
|
||||
l.Debug("unable to read from device buffer", "error", err)
|
||||
continue
|
||||
}
|
||||
// Write into CircBuffer.
|
||||
buf.Write(p)
|
||||
}
|
||||
}
|
||||
l.Debug("read bytes from device buffer", "bytes read", n)
|
||||
|
||||
func writeAudio(wg *sync.WaitGroup, file *os.File, buf *ring.Buffer, size int) {
|
||||
// Create a locally scoped bytes array.
|
||||
p := make([]byte, size*8)
|
||||
|
||||
var err error
|
||||
var n, m int
|
||||
for {
|
||||
n, err = buf.Read(p)
|
||||
// log.Println(n)
|
||||
if err.Error() == "EOF" {
|
||||
continue
|
||||
} else if err != nil {
|
||||
log.Println("failed to read from ring buffer:", err)
|
||||
continue
|
||||
}
|
||||
if n == 0 {
|
||||
log.Println("read nothing")
|
||||
continue
|
||||
}
|
||||
m, err = file.Write(p)
|
||||
n, err = output.Write(buf)
|
||||
if err != nil {
|
||||
log.Println("failed write to file:", err)
|
||||
wg.Done()
|
||||
} else if n != m {
|
||||
log.Printf("read and write not equal, n: %d, m: %d", n, m)
|
||||
l.Debug("unable to write to file", "error", err)
|
||||
continue
|
||||
}
|
||||
log.Printf("read %d bytes to file", m)
|
||||
l.Debug("wrote bytes to audio file", "bytes written", n)
|
||||
}
|
||||
}
|
||||
|
||||
func getDeviceStatus(dev *yalsa.Device) {
|
||||
// Get card numbers
|
||||
cardN := string(strings.Split(dev.Path, "C")[1][0])
|
||||
devN := string(strings.Split(dev.Path, "D")[1][0])
|
||||
|
||||
file, err := os.ReadFile(fmt.Sprintf("/proc/asound/card%s/pcm%sc/sub0/status", cardN, devN))
|
||||
if err != nil {
|
||||
log.Println("could not read status:", err)
|
||||
return
|
||||
}
|
||||
state := strings.Split(string(bytes.Trim(file, "state: ")), "\n")[0]
|
||||
log.Println("device state:", state)
|
||||
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -38,4 +38,6 @@ require (
|
|||
go.uber.org/zap v1.10.0 // indirect
|
||||
golang.org/x/image v0.0.0-20210216034530-4410531fe030 // indirect
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect
|
||||
periph.io/x/conn/v3 v3.7.0 // indirect
|
||||
periph.io/x/host/v3 v3.8.2 // indirect
|
||||
)
|
||||
|
|
4
go.sum
4
go.sum
|
@ -170,4 +170,8 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST
|
|||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
periph.io/x/conn/v3 v3.7.0 h1:f1EXLn4pkf7AEWwkol2gilCNZ0ElY+bxS4WE2PQXfrA=
|
||||
periph.io/x/conn/v3 v3.7.0/go.mod h1:ypY7UVxgDbP9PJGwFSVelRRagxyXYfttVh7hJZUHEhg=
|
||||
periph.io/x/host/v3 v3.8.2 h1:ayKUDzgUCN0g8+/xM9GTkWaOBhSLVcVHGTfjAOi8OsQ=
|
||||
periph.io/x/host/v3 v3.8.2/go.mod h1:yFL76AesNHR68PboofSWYaQTKmvPXsQH2Apvp/ls/K4=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
|
|
@ -270,6 +270,9 @@ type Config struct {
|
|||
// TransformMatrix describes the projective transformation matrix to extract a target from the
|
||||
// video data for turbidty calculations.
|
||||
TransformMatrix []float64
|
||||
|
||||
// AlsaTitle describes the ALSA device title. This is used to specify which recording device to use.
|
||||
AlsaTitle string
|
||||
}
|
||||
|
||||
// Validate checks for any errors in the config fields and defaults settings
|
||||
|
|
|
@ -322,7 +322,6 @@ func (s *mtsSender) output() {
|
|||
continue
|
||||
case pool.ErrTimeout:
|
||||
s.log.Warning("mtsSender: pool buffer read timeout")
|
||||
s.log.Debug("chunk equal nil", "bool", chunk == nil)
|
||||
continue
|
||||
default:
|
||||
s.log.Error("unexpected error", "error", err.Error())
|
||||
|
|
Loading…
Reference in New Issue