/* NAME audio_test.go AUTHOR Trek Hopton LICENSE This file is Copyright (C) 2019 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License in gpl.txt. If not, see [GNU licenses](http://www.gnu.org/licenses). */ package audio import ( "bytes" "errors" "os" "testing" "time" "bitbucket.org/ausocean/av/codec/codecutil" "bitbucket.org/ausocean/utils/logger" "github.com/yobert/alsa" ) // Check that a device exists with the given config parameters. func checkDevice(ac *Config) 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 } func TestDevice(t *testing.T) { // We want to open a device with a standard configuration. ac := &Config{ SampleRate: 8000, Channels: 1, RecPeriod: 0.3, BitDepth: 16, Codec: codecutil.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 audio Device, start, read/lex, and then stop it. l := logger.New(logger.Debug, os.Stderr) ai, err := NewDevice(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.Duration(ac.RecPeriod*float64(time.Second)) * time.Duration(n)) ai.Stop() } func TestNearestPowerOfTwo(t *testing.T) { testValues := []int{36, 47, 3, 46, 7, 2, 36, 757, 2464, 18980, 70000, 8192, 2048, 65536, -2048, -127, -1, 0, 1} testAnswers := []int{32, 32, 4, 32, 8, 2, 32, 512, 2048, 16384, 65536, 8192, 2048, 65536, 1, 1, 1, 1, 2} for i, v := range testValues { if r := nearestPowerOfTwo(v); testAnswers[i] != r { t.Errorf("test %v gave incorrect result: %v, should be %v", i, r, testAnswers[i]) } } }