"""Preserve original speech PCM/DMA output while sharing encoded flash spans.""" from pathlib import Path import hashlib import os import re import shutil import subprocess import tempfile import unittest import test_gps_voice_buttons as shared from test_button_voice_generator import select_vibration ROOT = Path(__file__).resolve().parents[1] CC, CXX = shutil.which('gcc'), shutil.which('g++') SANITIZERS = (['-fsanitize=address,undefined', '-fno-sanitize-recover=all', '-fno-omit-frame-pointer', '-fno-pie', '-no-pie'] if os.environ.get('MESH_VOICE_TEST_SANITIZERS') == '1' else []) # Pinned from the original contiguous approved catalogs and the original # decoder/player before any sharing changes. PCM is s16le; DMA words are u16le # at gain 2. These checks include every clip, final padding, IRQ refill and # interpolation tail, not hashes derived from the implementation under test. ORIGINAL_OUTPUT = { (0, False): ('481630ba68b1a29d5148fb1b552ca9bb78477ddc576bf9bad6d124d193dc994c', '7438e1cc35538956c8959adf9056aeffbd77c20e4fbd23b1204c3c17ab15a9c0'), (0, True): ('4e7ba541d3909bf8bbc4ae94c220f3a3d6a2304efaf53e3335a0844574475e87', '6b0419e83310946342b136661460eed5795fa92b23eb9da6f43056d840d0c025'), (16, False): ('f61a12157647ba21320ec65fb7a4bdcee260703ca593b57e5770af45076c7972', 'f8bdd21166fe8606622abfb8cff27136612e65e61e9f18d02e95c41e62897196'), (16, True): ('86e13b896a20c5c77ca9dae9d71c52a1da78f7603a8c8e260a6c6c74d51567d6', '10fb34b5487048a738a75c2bd4388c4ff370cbaebb54ed3a52006738dd86f425'), (24, False): ('e37d6bbd0c7f9ddd0018c7f50d3929b1deef27b405a7432c492b2fb67c46e11b', '2a7815a6ea01302b0cfe2d2bb3d6a57adeeec155ba70ac8aa9e1e3965d8d54be'), (24, True): ('59167abf199c939cc62b3b03d9dbfcffd973c495104f89de29a6dd852100cdf2', '2915281db72ebe103e7599a797f0413eb7245346ba55879c4a0a9ca1f61be293'), } @unittest.skipUnless(CC and CXX, 'Native C/C++ compilers are required') class Tests(unittest.TestCase): def test_every_original_phrase_and_full_dma_stream_remains_bit_identical(self): with tempfile.TemporaryDirectory() as temporary: directory = Path(temporary) (directory/'Arduino.h').write_text(shared.ARDUINO) (directory/'HardwarePWM.h').write_text(shared.PWM) for (rate, vibration), fingerprints in ORIGINAL_OUTPUT.items(): flags = ['-DMESH_BUTTON_AUDIO_HIL=1'] if rate: flags.append(f'-DMESH_GPS_VOICE_G726_BITRATE={rate}') if vibration: flags.append('-DHAS_DRV2605=1') objects = [] if rate: obj = directory/'g726.o' subprocess.run([CC, '-std=c99', '-Wall', '-Wextra', '-Werror', *SANITIZERS, *flags, '-I'+str(ROOT/'src'), '-c', str(ROOT/'src/helpers/ui/g726/g726_decoder.c'), '-o', str(obj)], check=True, timeout=30) objects.append(str(obj)) for pwm, fingerprint in enumerate(fingerprints): with self.subTest(rate=rate, vibration=vibration, pwm=bool(pwm)): binary = directory/'catalog' subprocess.run([CXX, '-std=c++17', '-Wall', '-Wextra', '-Werror', *SANITIZERS, *flags, *(['-DPWM_OUTPUT=1'] if pwm else []), '-I'+str(directory), '-I'+str(ROOT/'src'), str(ROOT/'test/fixtures/voice_prefixes/catalog.cpp'), *objects, '-o', str(binary)], check=True, timeout=30) result = subprocess.run([str(binary)], check=True, capture_output=True, timeout=30) self.assertEqual(hashlib.sha256(result.stdout).hexdigest(), fingerprint) def test_ima_seams_odd_lengths_truncation_and_invalid_metadata(self): source = r''' #include #include #include #include #include int main(){ using namespace mesh::audio; const uint8_t encoded[]={0x77,0x1f,0xca,0x26,0x84,0x92,0xbb}; for(unsigned samples:{1u,2u,3u,7u,13u,14u}){ VoiceDecoder original;original.begin({encoded,sizeof(encoded),samples}); std::vector expected; while(!original.done())expected.push_back(original.next()); for(size_t split=0;split prefix(encoded,encoded+split),suffix(encoded+split,encoded+split+tail); VoiceClip short_clip{tail?suffix.data():encoded,tail,samples,8000, split?prefix.data():nullptr,split}; decoder.begin(short_clip); unsigned count=0; while(!decoder.done()){assert(decoder.next()==expected[count++]);} assert(count==((split+tail)*2::max(), std::numeric_limits::max(),8000,encoded,1}; assert(huge.valid()&&huge.hasBytes(std::numeric_limits::max())); } ''' with tempfile.TemporaryDirectory() as temporary: directory = Path(temporary) path, binary = directory/'seams.cpp', directory/'seams' path.write_text(source) subprocess.run([CXX, '-std=c++17', '-Wall', '-Wextra', '-Werror', *SANITIZERS, '-I'+str(ROOT/'src'), str(path), '-o', str(binary)], check=True, timeout=30) subprocess.run([str(binary)], check=True, timeout=30) def test_only_profitable_shared_spans_are_stored_and_optional_sound_is_gated(self): expected = {0: (3135, 746, 1090), 16: (1535, 268, 545), 24: (1967, 427, 817)} for rate, sizes in expected.items(): if rate: source = (ROOT/'src/helpers/ui/G726VoiceData.h').read_text() source = source.split(f'#if MESH_GPS_VOICE_G726_BITRATE == {rate}\n')[1] source = source.split(f'#endif // {rate} kbps')[0] else: source = ((ROOT/'src/helpers/ui/GpsVoiceData.h').read_text() + '\n' + (ROOT/'src/helpers/ui/ButtonVoiceData.h').read_text()) for vibration in (False, True): body = select_vibration(source, vibration) arrays = {name:bytes.fromhex(' '.join(re.findall(r'0x([0-9a-f]{2})',data))) for name,data in re.findall(r'static const uint8_t (\w+)Data\[\] = \{(.*?)\};',body,re.S)} self.assertEqual(len(arrays['gps']), sizes[0]) self.assertEqual(len(arrays['advertPrefix']), sizes[1]) self.assertEqual('soundPrefix' in arrays, vibration) if vibration: self.assertEqual(len(arrays['soundPrefix']), sizes[2]) self.assertEqual(sum(name.startswith('gps') for name in arrays), 3) if __name__ == '__main__': unittest.main()