10a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom test import test_support 20a8c90248264a8b26970b4473770bcc3df8515fJosh Gaotest_support.requires('audio') 30a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 40a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom test.test_support import findfile 50a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 60a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoossaudiodev = test_support.import_module('ossaudiodev') 70a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 80a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport errno 90a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport sys 100a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport sunau 110a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport time 120a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport audioop 130a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport unittest 140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# Arggh, AFMT_S16_NE not defined on all platforms -- seems to be a 160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# fairly recent addition to OSS. 170a8c90248264a8b26970b4473770bcc3df8515fJosh Gaotry: 180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao from ossaudiodev import AFMT_S16_NE 190a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoexcept ImportError: 200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if sys.byteorder == "little": 210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao AFMT_S16_NE = ossaudiodev.AFMT_S16_LE 220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao AFMT_S16_NE = ossaudiodev.AFMT_S16_BE 240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 260a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef read_sound_file(path): 270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao with open(path, 'rb') as fp: 280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao au = sunau.open(fp) 290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao rate = au.getframerate() 300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao nchannels = au.getnchannels() 310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao encoding = au._encoding 320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao fp.seek(0) 330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao data = fp.read() 340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if encoding != sunau.AUDIO_FILE_ENCODING_MULAW_8: 360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise RuntimeError("Expect .au file with 8-bit mu-law samples") 370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Convert the data to 16-bit signed. 390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao data = audioop.ulaw2lin(data, 2) 400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return (data, rate, 16, nchannels) 410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 420a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass OSSAudioDevTests(unittest.TestCase): 430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def play_sound_file(self, data, rate, ssize, nchannels): 450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp = ossaudiodev.open('w') 470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except IOError, msg: 480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if msg.args[0] in (errno.EACCES, errno.ENOENT, 490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao errno.ENODEV, errno.EBUSY): 500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise unittest.SkipTest(msg) 510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise 520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # at least check that these methods can be invoked 540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.bufsize() 550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.obufcount() 560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.obuffree() 570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.getptr() 580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.fileno() 590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Make sure the read-only attributes work. 610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertFalse(dsp.closed) 620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(dsp.name, "/dev/dsp") 630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(dsp.mode, "w", "bad dsp.mode: %r" % dsp.mode) 640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # And make sure they're really read-only. 660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for attr in ('closed', 'name', 'mode'): 670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao setattr(dsp, attr, 42) 690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except TypeError: 700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.fail("dsp.%s not read-only" % attr) 730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Compute expected running time of sound sample (in seconds). 750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao expected_time = float(len(data)) / (ssize//8) / nchannels / rate 760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # set parameters based on .au file headers 780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.setparameters(AFMT_S16_NE, nchannels, rate) 790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(abs(expected_time - 3.51) < 1e-2, expected_time) 800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t1 = time.time() 810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.write(data) 820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.close() 830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t2 = time.time() 840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao elapsed_time = t2 - t1 850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao percent_diff = (abs(elapsed_time - expected_time) / expected_time) * 100 870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(percent_diff <= 10.0, 880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "elapsed time > 10% off of expected time") 890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def set_parameters(self, dsp): 910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Two configurations for testing: 920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # config1 (8-bit, mono, 8 kHz) should work on even the most 930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # ancient and crufty sound card, but maybe not on special- 940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # purpose high-end hardware 950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # config2 (16-bit, stereo, 44.1kHz) should work on all but the 960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # most ancient and crufty hardware 970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao config1 = (ossaudiodev.AFMT_U8, 1, 8000) 980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao config2 = (AFMT_S16_NE, 2, 44100) 990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for config in [config1, config2]: 1010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao (fmt, channels, rate) = config 1020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if (dsp.setfmt(fmt) == fmt and 1030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.channels(channels) == channels and 1040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.speed(rate) == rate): 1050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao break 1060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 1070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise RuntimeError("unable to set audio sampling parameters: " 1080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "you must have really weird audio hardware") 1090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # setparameters() should be able to set this configuration in 1110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # either strict or non-strict mode. 1120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao result = dsp.setparameters(fmt, channels, rate, False) 1130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(result, (fmt, channels, rate), 1140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "setparameters%r: returned %r" % (config, result)) 1150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao result = dsp.setparameters(fmt, channels, rate, True) 1170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(result, (fmt, channels, rate), 1180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "setparameters%r: returned %r" % (config, result)) 1190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def set_bad_parameters(self, dsp): 1210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Now try some configurations that are presumably bogus: eg. 300 1220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # channels currently exceeds even Hollywood's ambitions, and 1230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # negative sampling rate is utter nonsense. setparameters() should 1240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # accept these in non-strict mode, returning something other than 1250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # was requested, but should barf in strict mode. 1260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao fmt = AFMT_S16_NE 1270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao rate = 44100 1280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao channels = 2 1290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for config in [(fmt, 300, rate), # ridiculous nchannels 1300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao (fmt, -5, rate), # impossible nchannels 1310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao (fmt, channels, -50), # impossible rate 1320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ]: 1330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao (fmt, channels, rate) = config 1340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao result = dsp.setparameters(fmt, channels, rate, False) 1350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertNotEqual(result, config, 1360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "unexpectedly got requested configuration") 1370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 1390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao result = dsp.setparameters(fmt, channels, rate, True) 1400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except ossaudiodev.OSSAudioError, err: 1410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 1420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 1430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.fail("expected OSSAudioError") 1440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_playback(self): 1460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sound_info = read_sound_file(findfile('audiotest.au')) 1470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.play_sound_file(*sound_info) 1480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_set_parameters(self): 1500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp = ossaudiodev.open("w") 1510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 1520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.set_parameters(dsp) 1530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Disabled because it fails under Linux 2.6 with ALSA's OSS 1550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # emulation layer. 1560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao #self.set_bad_parameters(dsp) 1570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao finally: 1580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.close() 1590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(dsp.closed) 1600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1620a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef test_main(): 1630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 1640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp = ossaudiodev.open('w') 1650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except (ossaudiodev.error, IOError), msg: 1660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if msg.args[0] in (errno.EACCES, errno.ENOENT, 1670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao errno.ENODEV, errno.EBUSY): 1680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise unittest.SkipTest(msg) 1690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise 1700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao dsp.close() 1710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao test_support.run_unittest(__name__) 1720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1730a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoif __name__ == "__main__": 1740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao test_main() 175