revid: changed writeRates and recPeriods to floats

This commit is contained in:
Trek H 2019-05-21 12:39:10 +09:30
parent 7ba9d023a3
commit c58c573cd7
6 changed files with 83 additions and 34 deletions

View File

@ -138,7 +138,7 @@ func handleFlags() revid.Config {
// Audio specific flags. // Audio specific flags.
sampleRatePtr = flag.Int("SampleRate", 48000, "Sample rate of recorded audio") sampleRatePtr = flag.Int("SampleRate", 48000, "Sample rate of recorded audio")
channelsPtr = flag.Int("Channels", 1, "Record in Mono or Stereo (1 or 2)") channelsPtr = flag.Int("Channels", 1, "Record in Mono or Stereo (1 or 2)")
recPeriodPtr = flag.Int("recPeriod", 1, "How many seconds to record at a time") recPeriodPtr = flag.Float64("recPeriod", 1, "How many seconds to record at a time")
bitDepthPtr = flag.Int("bitDepth", 16, "Bit Depth to record audio at.") bitDepthPtr = flag.Int("bitDepth", 16, "Bit Depth to record audio at.")
) )
@ -209,9 +209,9 @@ func handleFlags() revid.Config {
switch *inputPtr { switch *inputPtr {
case "Audio": case "Audio":
cfg.WriteRate = uint(*recPeriodPtr) cfg.WriteRate = 1.0 / (*recPeriodPtr)
default: default:
cfg.WriteRate = *frameRatePtr cfg.WriteRate = float64(*frameRatePtr)
} }
if len(outputs) == 0 { if len(outputs) == 0 {

View File

@ -52,6 +52,8 @@ const (
stopped stopped
) )
var rates = [8]int{8000, 16000, 32000, 44100, 48000, 88200, 96000, 192000}
var log *logger.Logger var log *logger.Logger
// audioDevice holds everything we need to know about the audio input stream. // audioDevice holds everything we need to know about the audio input stream.
@ -141,7 +143,7 @@ func (a *audioDevice) Start() {
a.mu.Unlock() a.mu.Unlock()
} }
// Stop will stop recording audio and close // Stop will stop recording audio and close the device
func (a *audioDevice) Stop() { func (a *audioDevice) Stop() {
a.mu.Lock() a.mu.Lock()
a.mode = stopped a.mode = stopped
@ -178,7 +180,7 @@ func (a *audioDevice) open() error {
for _, card := range cards { for _, card := range cards {
devices, err := card.Devices() devices, err := card.Devices()
if err != nil { if err != nil {
return err continue
} }
for _, dev := range devices { for _, dev := range devices {
if dev.Type != alsa.PCM || !dev.Record { if dev.Type != alsa.PCM || !dev.Record {
@ -214,8 +216,7 @@ func (a *audioDevice) open() error {
// so that it can be easily downsampled to the wanted rate. // so that it can be easily downsampled to the wanted rate.
// Note: if a card thinks it can record at a rate but can't actually, this can cause a failure. Eg. // Note: if a card thinks it can record at a rate but can't actually, this can cause a failure. Eg.
// the audioinjector is supposed to record at 8000Hz and 16000Hz but it can't due to a firmware issue, // the audioinjector is supposed to record at 8000Hz and 16000Hz but it can't due to a firmware issue,
// to fix this 8000 and 16000 must be removed from this slice. // to fix this 8000 and 16000 must be removed from the rates slice.
rates := [8]int{8000, 16000, 32000, 44100, 48000, 88200, 96000, 192000}
foundRate := false foundRate := false
for i := 0; i < len(rates) && !foundRate; i++ { for i := 0; i < len(rates) && !foundRate; i++ {
if rates[i] < a.SampleRate { if rates[i] < a.SampleRate {

View File

@ -3,32 +3,80 @@ package revid
import ( import (
"testing" "testing"
"bitbucket.org/ausocean/av/container/mts" "github.com/yobert/alsa"
"bitbucket.org/ausocean/av/container/mts/meta"
"bitbucket.org/ausocean/iot/pi/netsender"
) )
func TestAudioPipeline(t *testing.T) { func TestAudioDevice(t *testing.T) {
mts.Meta = meta.New() // We want to open a device with a standard configuration.
var logger testLogger ac := &AudioConfig{
ns, err := netsender.New(&logger, nil, nil, nil) SampleRate: 8000,
if err != nil { Channels: 1,
t.Errorf("netsender.New failed with error %v", err) RecPeriod: 1,
BitDepth: 16,
Codec: ADPCM,
} }
var c Config // Check that a device exists with the desired parameters.
c.Logger = &logger cards, err := alsa.OpenCards()
c.Input = File
c.InputPath = "../../test/test-data/av/input/original_8kHz_adpcm_test.pcm"
c.Outputs = []uint8{File}
c.OutputPath = "./test-temp"
rv, err := New(c, ns)
if err != nil { if err != nil {
t.Errorf("revid.New failed with error %v", err) t.Skip("skipping, no audio card found")
} else if rv == nil {
t.Errorf("revid.New did not return a new revid")
} }
defer alsa.CloseCards(cards)
var testDev *alsa.Device
for _, card := range cards {
devices, err := card.Devices()
if err != nil {
continue
}
for _, dev := range devices {
if dev.Type != alsa.PCM || !dev.Record {
continue
}
testDev = dev
break
}
}
if testDev == nil {
t.Skip("skipping, no suitable audio device found")
}
_, err = testDev.NegotiateChannels(2)
if err != nil {
t.Skip("skipping, no suitable audio device found")
}
foundRate := false
for i := 0; i < len(rates) && !foundRate; i++ {
if rates[i] < ac.SampleRate {
continue
}
if rates[i]%ac.SampleRate == 0 {
_, err = testDev.NegotiateRate(rates[i])
if err == nil {
foundRate = true
}
}
}
if !foundRate {
_, err = testDev.NegotiateRate(defaultSampleRate)
if err != nil {
t.Skip("skipping, no suitable audio device found")
}
}
_, err = testDev.NegotiateFormat(alsa.S16_LE)
if err != nil {
t.Skip("skipping, no suitable audio device found")
}
_, err = testDev.NegotiateBufferSize(8192, 16384)
if err != nil {
t.Skip("skipping, no suitable audio device found")
}
if err = testDev.Prepare(); err != nil {
t.Skip("skipping, no suitable audio device found")
}
testDev.Close()
rv.Stop() ai := NewAudioDevice(ac)
ai.Start()
ai.Stop()
} }

View File

@ -53,7 +53,7 @@ type Config struct {
IntraRefreshPeriod uint IntraRefreshPeriod uint
RtpAddress string RtpAddress string
SendRetry bool SendRetry bool
WriteRate uint // How many times a second revid encoders will be written to. WriteRate float64 // How many times a second revid encoders will be written to.
// Video // Video
Height uint Height uint

View File

@ -161,8 +161,8 @@ func (r *Revid) reset(config Config) error {
r.config.Logger.SetLevel(config.LogLevel) r.config.Logger.SetLevel(config.LogLevel)
err = r.setupPipeline( err = r.setupPipeline(
func(dst io.WriteCloser, fps, medType int) (io.WriteCloser, error) { func(dst io.WriteCloser, fps float64, medType int) (io.WriteCloser, error) {
e := mts.NewEncoder(dst, float64(fps), medType) e := mts.NewEncoder(dst, fps, medType)
return e, nil return e, nil
}, },
func(dst io.WriteCloser, fps int) (io.WriteCloser, error) { func(dst io.WriteCloser, fps int) (io.WriteCloser, error) {
@ -196,7 +196,7 @@ func (r *Revid) setConfig(config Config) error {
// mtsEnc and flvEnc will be called to obtain an mts encoder and flv encoder // mtsEnc and flvEnc will be called to obtain an mts encoder and flv encoder
// respectively. multiWriter will be used to create an ioext.multiWriteCloser // respectively. multiWriter will be used to create an ioext.multiWriteCloser
// so that encoders can write to multiple senders. // so that encoders can write to multiple senders.
func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate, mediaType int) (io.WriteCloser, error), flvEnc func(dst io.WriteCloser, rate int) (io.WriteCloser, error), multiWriter func(...io.WriteCloser) io.WriteCloser) error { func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64, mediaType int) (io.WriteCloser, error), flvEnc func(dst io.WriteCloser, rate int) (io.WriteCloser, error), multiWriter func(...io.WriteCloser) io.WriteCloser) error {
// encoders will hold the encoders that are required for revid's current // encoders will hold the encoders that are required for revid's current
// configuration. // configuration.
var encoders []io.WriteCloser var encoders []io.WriteCloser
@ -246,7 +246,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate, mediaType in
} else { } else {
mediaType = mts.Video mediaType = mts.Video
} }
e, _ := mtsEnc(mw, int(r.config.WriteRate), mediaType) e, _ := mtsEnc(mw, r.config.WriteRate, mediaType)
encoders = append(encoders, e) encoders = append(encoders, e)
} }

View File

@ -232,7 +232,7 @@ func TestResetEncoderSenderSetup(t *testing.T) {
// This logic is what we want to check. // This logic is what we want to check.
err = rv.setupPipeline( err = rv.setupPipeline(
func(dst io.WriteCloser, rate int, mediaType int) (io.WriteCloser, error) { func(dst io.WriteCloser, rate float64, mediaType int) (io.WriteCloser, error) {
return &tstMtsEncoder{dst: dst}, nil return &tstMtsEncoder{dst: dst}, nil
}, },
func(dst io.WriteCloser, rate int) (io.WriteCloser, error) { func(dst io.WriteCloser, rate int) (io.WriteCloser, error) {