Files
rpi-buildroot/support/testing/tests/package/test_audio_codec_base.py
Julien Olivain 4a285b160f support/testing: test_audio_codec_base.py: new helper class
This is a helper class providing a template for testing audio codec
programs such as lame mp3 encoder, flac tools, ogg vorbis-tools, ...

Signed-off-by: Julien Olivain <ju.o@free.fr>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
2024-08-06 23:21:33 +02:00

87 lines
3.2 KiB
Python

import math
import os
import infra.basetest
class TestAudioCodecBase(infra.basetest.BRTest):
"""Common class to test an audio codec package.
This base class builds a Buildroot system image containing the
package enabled in its config, start the emulator, login to it. It
prepares an input test WAV file containing a tone. This WAV file
is encoded into a new output file in the native encoder format. It
is then decoded to a new output WAV file. This final output WAV
file is checked to contain the expected tone generated in the
initial input WAV file. There is no specific check about file
size, nor audio quality. The acceptance criteria is the
recognition of the tone. Note: the tone generation is made with
the Sox package, and the tone recognition is made with the Aubio
package.
Each test case that inherits from this class must have:
__test__ = True - to let nose2 know that it is a test case
config - defconfig fragment with the packages to run the test
encode_test() - the function that runs the encoder and produces an
encoded file.
decode_test() - the function that runs the decoder and produces a
decode file.
"""
__test__ = False
config = infra.basetest.BASIC_TOOLCHAIN_CONFIG + \
"""
BR2_PACKAGE_AUBIO=y
BR2_PACKAGE_SOX=y
BR2_TARGET_ROOTFS_CPIO=y
# BR2_TARGET_ROOTFS_TAR is not set
"""
input_file = "reference.wav"
decoded_file = "decoded.wav"
tone_freq = 440 # General Midi note A3
def login(self):
cpio_file = os.path.join(self.builddir, "images", "rootfs.cpio")
self.emulator.boot(arch="armv5",
kernel="builtin",
options=["-initrd", cpio_file])
self.emulator.login()
def test_run(self):
self.login()
self.prepare_data()
self.encode_test(self.input_file)
self.decode_test(self.decoded_file)
self.check_test()
def prepare_data(self):
# Generate a sinusoidal tone.
cmd = "sox -V -r 48000 -n -b 16 -c 1 "
cmd += self.input_file
cmd += f" synth 3 sin {self.tone_freq} vol -10dB"
self.assertRunOk(cmd)
def encode_test(self, input_filename):
msg = "method must be implemented in derived class"
raise NotImplementedError(msg)
def decode_test(self, output_filename):
msg = "method must be implemented in derived class"
raise NotImplementedError(msg)
def note_from_freq(self, freq):
"""Return a note number from the input frequency in Hertz."""
return round((12 * math.log(freq / 440) / math.log(2)) + 69)
def check_test(self):
expected_note = self.note_from_freq(self.tone_freq)
out, ret = self.emulator.run(f"aubionotes {self.decoded_file}", timeout=20)
self.assertEqual(ret, 0)
note_found = False
for line in out:
values = line.split()
if len(values) == 3:
note = round(float(values[0]))
if note == expected_note:
note_found = True
self.assertTrue(note_found, "The expected note was not found")