17db96d56Sopenharmony_cifrom test import support 27db96d56Sopenharmony_cifrom test.support import import_helper, warnings_helper 37db96d56Sopenharmony_ciimport warnings 47db96d56Sopenharmony_cisupport.requires('audio') 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_cifrom test.support import findfile 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_ciwith warnings.catch_warnings(): 97db96d56Sopenharmony_ci warnings.simplefilter("ignore", DeprecationWarning) 107db96d56Sopenharmony_ci ossaudiodev = import_helper.import_module('ossaudiodev') 117db96d56Sopenharmony_ciaudioop = warnings_helper.import_deprecated('audioop') 127db96d56Sopenharmony_cisunau = warnings_helper.import_deprecated('sunau') 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ciimport errno 157db96d56Sopenharmony_ciimport sys 167db96d56Sopenharmony_ciimport time 177db96d56Sopenharmony_ciimport unittest 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ci# Arggh, AFMT_S16_NE not defined on all platforms -- seems to be a 207db96d56Sopenharmony_ci# fairly recent addition to OSS. 217db96d56Sopenharmony_citry: 227db96d56Sopenharmony_ci from ossaudiodev import AFMT_S16_NE 237db96d56Sopenharmony_ciexcept ImportError: 247db96d56Sopenharmony_ci if sys.byteorder == "little": 257db96d56Sopenharmony_ci AFMT_S16_NE = ossaudiodev.AFMT_S16_LE 267db96d56Sopenharmony_ci else: 277db96d56Sopenharmony_ci AFMT_S16_NE = ossaudiodev.AFMT_S16_BE 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_cidef read_sound_file(path): 317db96d56Sopenharmony_ci with open(path, 'rb') as fp: 327db96d56Sopenharmony_ci au = sunau.open(fp) 337db96d56Sopenharmony_ci rate = au.getframerate() 347db96d56Sopenharmony_ci nchannels = au.getnchannels() 357db96d56Sopenharmony_ci encoding = au._encoding 367db96d56Sopenharmony_ci fp.seek(0) 377db96d56Sopenharmony_ci data = fp.read() 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci if encoding != sunau.AUDIO_FILE_ENCODING_MULAW_8: 407db96d56Sopenharmony_ci raise RuntimeError("Expect .au file with 8-bit mu-law samples") 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci # Convert the data to 16-bit signed. 437db96d56Sopenharmony_ci data = audioop.ulaw2lin(data, 2) 447db96d56Sopenharmony_ci return (data, rate, 16, nchannels) 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ciclass OSSAudioDevTests(unittest.TestCase): 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_ci def play_sound_file(self, data, rate, ssize, nchannels): 497db96d56Sopenharmony_ci try: 507db96d56Sopenharmony_ci dsp = ossaudiodev.open('w') 517db96d56Sopenharmony_ci except OSError as msg: 527db96d56Sopenharmony_ci if msg.args[0] in (errno.EACCES, errno.ENOENT, 537db96d56Sopenharmony_ci errno.ENODEV, errno.EBUSY): 547db96d56Sopenharmony_ci raise unittest.SkipTest(msg) 557db96d56Sopenharmony_ci raise 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ci # at least check that these methods can be invoked 587db96d56Sopenharmony_ci dsp.bufsize() 597db96d56Sopenharmony_ci dsp.obufcount() 607db96d56Sopenharmony_ci dsp.obuffree() 617db96d56Sopenharmony_ci dsp.getptr() 627db96d56Sopenharmony_ci dsp.fileno() 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_ci # Make sure the read-only attributes work. 657db96d56Sopenharmony_ci self.assertFalse(dsp.closed) 667db96d56Sopenharmony_ci self.assertEqual(dsp.name, "/dev/dsp") 677db96d56Sopenharmony_ci self.assertEqual(dsp.mode, "w", "bad dsp.mode: %r" % dsp.mode) 687db96d56Sopenharmony_ci 697db96d56Sopenharmony_ci # And make sure they're really read-only. 707db96d56Sopenharmony_ci for attr in ('closed', 'name', 'mode'): 717db96d56Sopenharmony_ci try: 727db96d56Sopenharmony_ci setattr(dsp, attr, 42) 737db96d56Sopenharmony_ci except (TypeError, AttributeError): 747db96d56Sopenharmony_ci pass 757db96d56Sopenharmony_ci else: 767db96d56Sopenharmony_ci self.fail("dsp.%s not read-only" % attr) 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci # Compute expected running time of sound sample (in seconds). 797db96d56Sopenharmony_ci expected_time = float(len(data)) / (ssize/8) / nchannels / rate 807db96d56Sopenharmony_ci 817db96d56Sopenharmony_ci # set parameters based on .au file headers 827db96d56Sopenharmony_ci dsp.setparameters(AFMT_S16_NE, nchannels, rate) 837db96d56Sopenharmony_ci self.assertTrue(abs(expected_time - 3.51) < 1e-2, expected_time) 847db96d56Sopenharmony_ci t1 = time.monotonic() 857db96d56Sopenharmony_ci dsp.write(data) 867db96d56Sopenharmony_ci dsp.close() 877db96d56Sopenharmony_ci t2 = time.monotonic() 887db96d56Sopenharmony_ci elapsed_time = t2 - t1 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci percent_diff = (abs(elapsed_time - expected_time) / expected_time) * 100 917db96d56Sopenharmony_ci self.assertTrue(percent_diff <= 10.0, 927db96d56Sopenharmony_ci "elapsed time (%s) > 10%% off of expected time (%s)" % 937db96d56Sopenharmony_ci (elapsed_time, expected_time)) 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci def set_parameters(self, dsp): 967db96d56Sopenharmony_ci # Two configurations for testing: 977db96d56Sopenharmony_ci # config1 (8-bit, mono, 8 kHz) should work on even the most 987db96d56Sopenharmony_ci # ancient and crufty sound card, but maybe not on special- 997db96d56Sopenharmony_ci # purpose high-end hardware 1007db96d56Sopenharmony_ci # config2 (16-bit, stereo, 44.1kHz) should work on all but the 1017db96d56Sopenharmony_ci # most ancient and crufty hardware 1027db96d56Sopenharmony_ci config1 = (ossaudiodev.AFMT_U8, 1, 8000) 1037db96d56Sopenharmony_ci config2 = (AFMT_S16_NE, 2, 44100) 1047db96d56Sopenharmony_ci 1057db96d56Sopenharmony_ci for config in [config1, config2]: 1067db96d56Sopenharmony_ci (fmt, channels, rate) = config 1077db96d56Sopenharmony_ci if (dsp.setfmt(fmt) == fmt and 1087db96d56Sopenharmony_ci dsp.channels(channels) == channels and 1097db96d56Sopenharmony_ci dsp.speed(rate) == rate): 1107db96d56Sopenharmony_ci break 1117db96d56Sopenharmony_ci else: 1127db96d56Sopenharmony_ci raise RuntimeError("unable to set audio sampling parameters: " 1137db96d56Sopenharmony_ci "you must have really weird audio hardware") 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci # setparameters() should be able to set this configuration in 1167db96d56Sopenharmony_ci # either strict or non-strict mode. 1177db96d56Sopenharmony_ci result = dsp.setparameters(fmt, channels, rate, False) 1187db96d56Sopenharmony_ci self.assertEqual(result, (fmt, channels, rate), 1197db96d56Sopenharmony_ci "setparameters%r: returned %r" % (config, result)) 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci result = dsp.setparameters(fmt, channels, rate, True) 1227db96d56Sopenharmony_ci self.assertEqual(result, (fmt, channels, rate), 1237db96d56Sopenharmony_ci "setparameters%r: returned %r" % (config, result)) 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_ci def set_bad_parameters(self, dsp): 1267db96d56Sopenharmony_ci # Now try some configurations that are presumably bogus: eg. 300 1277db96d56Sopenharmony_ci # channels currently exceeds even Hollywood's ambitions, and 1287db96d56Sopenharmony_ci # negative sampling rate is utter nonsense. setparameters() should 1297db96d56Sopenharmony_ci # accept these in non-strict mode, returning something other than 1307db96d56Sopenharmony_ci # was requested, but should barf in strict mode. 1317db96d56Sopenharmony_ci fmt = AFMT_S16_NE 1327db96d56Sopenharmony_ci rate = 44100 1337db96d56Sopenharmony_ci channels = 2 1347db96d56Sopenharmony_ci for config in [(fmt, 300, rate), # ridiculous nchannels 1357db96d56Sopenharmony_ci (fmt, -5, rate), # impossible nchannels 1367db96d56Sopenharmony_ci (fmt, channels, -50), # impossible rate 1377db96d56Sopenharmony_ci ]: 1387db96d56Sopenharmony_ci (fmt, channels, rate) = config 1397db96d56Sopenharmony_ci result = dsp.setparameters(fmt, channels, rate, False) 1407db96d56Sopenharmony_ci self.assertNotEqual(result, config, 1417db96d56Sopenharmony_ci "unexpectedly got requested configuration") 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci try: 1447db96d56Sopenharmony_ci result = dsp.setparameters(fmt, channels, rate, True) 1457db96d56Sopenharmony_ci except ossaudiodev.OSSAudioError as err: 1467db96d56Sopenharmony_ci pass 1477db96d56Sopenharmony_ci else: 1487db96d56Sopenharmony_ci self.fail("expected OSSAudioError") 1497db96d56Sopenharmony_ci 1507db96d56Sopenharmony_ci def test_playback(self): 1517db96d56Sopenharmony_ci sound_info = read_sound_file(findfile('audiotest.au')) 1527db96d56Sopenharmony_ci self.play_sound_file(*sound_info) 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci def test_set_parameters(self): 1557db96d56Sopenharmony_ci dsp = ossaudiodev.open("w") 1567db96d56Sopenharmony_ci try: 1577db96d56Sopenharmony_ci self.set_parameters(dsp) 1587db96d56Sopenharmony_ci 1597db96d56Sopenharmony_ci # Disabled because it fails under Linux 2.6 with ALSA's OSS 1607db96d56Sopenharmony_ci # emulation layer. 1617db96d56Sopenharmony_ci #self.set_bad_parameters(dsp) 1627db96d56Sopenharmony_ci finally: 1637db96d56Sopenharmony_ci dsp.close() 1647db96d56Sopenharmony_ci self.assertTrue(dsp.closed) 1657db96d56Sopenharmony_ci 1667db96d56Sopenharmony_ci def test_mixer_methods(self): 1677db96d56Sopenharmony_ci # Issue #8139: ossaudiodev didn't initialize its types properly, 1687db96d56Sopenharmony_ci # therefore some methods were unavailable. 1697db96d56Sopenharmony_ci with ossaudiodev.openmixer() as mixer: 1707db96d56Sopenharmony_ci self.assertGreaterEqual(mixer.fileno(), 0) 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci def test_with(self): 1737db96d56Sopenharmony_ci with ossaudiodev.open('w') as dsp: 1747db96d56Sopenharmony_ci pass 1757db96d56Sopenharmony_ci self.assertTrue(dsp.closed) 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_ci def test_on_closed(self): 1787db96d56Sopenharmony_ci dsp = ossaudiodev.open('w') 1797db96d56Sopenharmony_ci dsp.close() 1807db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.fileno) 1817db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.read, 1) 1827db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.write, b'x') 1837db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.writeall, b'x') 1847db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.bufsize) 1857db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.obufcount) 1867db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.obufcount) 1877db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.obuffree) 1887db96d56Sopenharmony_ci self.assertRaises(ValueError, dsp.getptr) 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ci mixer = ossaudiodev.openmixer() 1917db96d56Sopenharmony_ci mixer.close() 1927db96d56Sopenharmony_ci self.assertRaises(ValueError, mixer.fileno) 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_cidef setUpModule(): 1957db96d56Sopenharmony_ci try: 1967db96d56Sopenharmony_ci dsp = ossaudiodev.open('w') 1977db96d56Sopenharmony_ci except (ossaudiodev.error, OSError) as msg: 1987db96d56Sopenharmony_ci if msg.args[0] in (errno.EACCES, errno.ENOENT, 1997db96d56Sopenharmony_ci errno.ENODEV, errno.EBUSY): 2007db96d56Sopenharmony_ci raise unittest.SkipTest(msg) 2017db96d56Sopenharmony_ci raise 2027db96d56Sopenharmony_ci dsp.close() 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ciif __name__ == "__main__": 2057db96d56Sopenharmony_ci unittest.main() 206