package revid import ( "bytes" "errors" "fmt" "os" "runtime" "testing" "time" "bitbucket.org/ausocean/av/codec/codecutil" "github.com/yobert/alsa" ) // Check that a device exists with the given config parameters. func checkDevice(ac *AudioConfig) error { cards, err := alsa.OpenCards() if err != nil { return errors.New("no audio cards found") } 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 { return errors.New("no suitable device found") } err = testDev.Open() if err != nil { return err } _, err = testDev.NegotiateChannels(2) if err != nil { return err } 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 { return err } } var aFmt alsa.FormatType switch ac.BitDepth { case 16: aFmt = alsa.S16_LE case 32: aFmt = alsa.S32_LE default: return errors.New("unsupported bitdepth") } _, err = testDev.NegotiateFormat(aFmt) if err != nil { return err } _, err = testDev.NegotiateBufferSize(8192, 16384) if err != nil { return err } if err = testDev.Prepare(); err != nil { return err } if testDev != nil { testDev.Close() } return nil } // rTestLogger implements a revid.Logger. type rTestLogger struct{} func (tl rTestLogger) SetLevel(level int8) {} func (tl rTestLogger) Log(level int8, msg string, params ...interface{}) { logLevels := [...]string{"Debug", "Info", "Warn", "Error", "", "", "Fatal"} if level < -1 || level > 5 { panic("Invalid log level") } if !silent { fmt.Printf("%s: %s\n", logLevels[level+1], msg) } if level == 5 { buf := make([]byte, 1<<16) size := runtime.Stack(buf, true) fmt.Printf("%s\n", string(buf[:size])) os.Exit(1) } } func TestAudioDevice(t *testing.T) { // We want to open a device with a standard configuration. ac := &AudioConfig{ SampleRate: 8000, Channels: 1, RecPeriod: 0.5, BitDepth: 16, Codec: ADPCM, } n := 2 // Number of periods to wait while recording. // Skip if there are no suitable devices to test with. err := checkDevice(ac) if err != nil { t.Skip(err) } // Create a new audioDevice, start, read/lex, and then stop it. var l rTestLogger ai, err := NewAudioDevice(ac, l) if err != nil { t.Error(err) } dst := bytes.NewBuffer(make([]byte, 0)) err = ai.Start() if err != nil { t.Error(err) } go codecutil.LexBytes(dst, ai, time.Duration(ac.RecPeriod*float64(time.Second)), ai.ChunkSize()) time.Sleep(time.Second * time.Duration(ac.RecPeriod) * time.Duration(n)) ai.Stop() }