(root)/
Python-3.11.7/
Lib/
test/
test_ossaudiodev.py
       1  from test import support
       2  from test.support import import_helper, warnings_helper
       3  import warnings
       4  support.requires('audio')
       5  
       6  from test.support import findfile
       7  
       8  with warnings.catch_warnings():
       9      warnings.simplefilter("ignore", DeprecationWarning)
      10      ossaudiodev = import_helper.import_module('ossaudiodev')
      11  audioop = warnings_helper.import_deprecated('audioop')
      12  sunau = warnings_helper.import_deprecated('sunau')
      13  
      14  import errno
      15  import sys
      16  import time
      17  import unittest
      18  
      19  # Arggh, AFMT_S16_NE not defined on all platforms -- seems to be a
      20  # fairly recent addition to OSS.
      21  try:
      22      from ossaudiodev import AFMT_S16_NE
      23  except ImportError:
      24      if sys.byteorder == "little":
      25          AFMT_S16_NE = ossaudiodev.AFMT_S16_LE
      26      else:
      27          AFMT_S16_NE = ossaudiodev.AFMT_S16_BE
      28  
      29  
      30  def read_sound_file(path):
      31      with open(path, 'rb') as fp:
      32          au = sunau.open(fp)
      33          rate = au.getframerate()
      34          nchannels = au.getnchannels()
      35          encoding = au._encoding
      36          fp.seek(0)
      37          data = fp.read()
      38  
      39      if encoding != sunau.AUDIO_FILE_ENCODING_MULAW_8:
      40          raise RuntimeError("Expect .au file with 8-bit mu-law samples")
      41  
      42      # Convert the data to 16-bit signed.
      43      data = audioop.ulaw2lin(data, 2)
      44      return (data, rate, 16, nchannels)
      45  
      46  class ESC[4;38;5;81mOSSAudioDevTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      47  
      48      def play_sound_file(self, data, rate, ssize, nchannels):
      49          try:
      50              dsp = ossaudiodev.open('w')
      51          except OSError as msg:
      52              if msg.args[0] in (errno.EACCES, errno.ENOENT,
      53                                 errno.ENODEV, errno.EBUSY):
      54                  raise unittest.SkipTest(msg)
      55              raise
      56  
      57          # at least check that these methods can be invoked
      58          dsp.bufsize()
      59          dsp.obufcount()
      60          dsp.obuffree()
      61          dsp.getptr()
      62          dsp.fileno()
      63  
      64          # Make sure the read-only attributes work.
      65          self.assertFalse(dsp.closed)
      66          self.assertEqual(dsp.name, "/dev/dsp")
      67          self.assertEqual(dsp.mode, "w", "bad dsp.mode: %r" % dsp.mode)
      68  
      69          # And make sure they're really read-only.
      70          for attr in ('closed', 'name', 'mode'):
      71              try:
      72                  setattr(dsp, attr, 42)
      73              except (TypeError, AttributeError):
      74                  pass
      75              else:
      76                  self.fail("dsp.%s not read-only" % attr)
      77  
      78          # Compute expected running time of sound sample (in seconds).
      79          expected_time = float(len(data)) / (ssize/8) / nchannels / rate
      80  
      81          # set parameters based on .au file headers
      82          dsp.setparameters(AFMT_S16_NE, nchannels, rate)
      83          self.assertTrue(abs(expected_time - 3.51) < 1e-2, expected_time)
      84          t1 = time.monotonic()
      85          dsp.write(data)
      86          dsp.close()
      87          t2 = time.monotonic()
      88          elapsed_time = t2 - t1
      89  
      90          percent_diff = (abs(elapsed_time - expected_time) / expected_time) * 100
      91          self.assertTrue(percent_diff <= 10.0,
      92                          "elapsed time (%s) > 10%% off of expected time (%s)" %
      93                          (elapsed_time, expected_time))
      94  
      95      def set_parameters(self, dsp):
      96          # Two configurations for testing:
      97          #   config1 (8-bit, mono, 8 kHz) should work on even the most
      98          #      ancient and crufty sound card, but maybe not on special-
      99          #      purpose high-end hardware
     100          #   config2 (16-bit, stereo, 44.1kHz) should work on all but the
     101          #      most ancient and crufty hardware
     102          config1 = (ossaudiodev.AFMT_U8, 1, 8000)
     103          config2 = (AFMT_S16_NE, 2, 44100)
     104  
     105          for config in [config1, config2]:
     106              (fmt, channels, rate) = config
     107              if (dsp.setfmt(fmt) == fmt and
     108                  dsp.channels(channels) == channels and
     109                  dsp.speed(rate) == rate):
     110                  break
     111          else:
     112              raise RuntimeError("unable to set audio sampling parameters: "
     113                                 "you must have really weird audio hardware")
     114  
     115          # setparameters() should be able to set this configuration in
     116          # either strict or non-strict mode.
     117          result = dsp.setparameters(fmt, channels, rate, False)
     118          self.assertEqual(result, (fmt, channels, rate),
     119                           "setparameters%r: returned %r" % (config, result))
     120  
     121          result = dsp.setparameters(fmt, channels, rate, True)
     122          self.assertEqual(result, (fmt, channels, rate),
     123                           "setparameters%r: returned %r" % (config, result))
     124  
     125      def set_bad_parameters(self, dsp):
     126          # Now try some configurations that are presumably bogus: eg. 300
     127          # channels currently exceeds even Hollywood's ambitions, and
     128          # negative sampling rate is utter nonsense.  setparameters() should
     129          # accept these in non-strict mode, returning something other than
     130          # was requested, but should barf in strict mode.
     131          fmt = AFMT_S16_NE
     132          rate = 44100
     133          channels = 2
     134          for config in [(fmt, 300, rate),       # ridiculous nchannels
     135                         (fmt, -5, rate),        # impossible nchannels
     136                         (fmt, channels, -50),   # impossible rate
     137                        ]:
     138              (fmt, channels, rate) = config
     139              result = dsp.setparameters(fmt, channels, rate, False)
     140              self.assertNotEqual(result, config,
     141                               "unexpectedly got requested configuration")
     142  
     143              try:
     144                  result = dsp.setparameters(fmt, channels, rate, True)
     145              except ossaudiodev.OSSAudioError as err:
     146                  pass
     147              else:
     148                  self.fail("expected OSSAudioError")
     149  
     150      def test_playback(self):
     151          sound_info = read_sound_file(findfile('audiotest.au'))
     152          self.play_sound_file(*sound_info)
     153  
     154      def test_set_parameters(self):
     155          dsp = ossaudiodev.open("w")
     156          try:
     157              self.set_parameters(dsp)
     158  
     159              # Disabled because it fails under Linux 2.6 with ALSA's OSS
     160              # emulation layer.
     161              #self.set_bad_parameters(dsp)
     162          finally:
     163              dsp.close()
     164              self.assertTrue(dsp.closed)
     165  
     166      def test_mixer_methods(self):
     167          # Issue #8139: ossaudiodev didn't initialize its types properly,
     168          # therefore some methods were unavailable.
     169          with ossaudiodev.openmixer() as mixer:
     170              self.assertGreaterEqual(mixer.fileno(), 0)
     171  
     172      def test_with(self):
     173          with ossaudiodev.open('w') as dsp:
     174              pass
     175          self.assertTrue(dsp.closed)
     176  
     177      def test_on_closed(self):
     178          dsp = ossaudiodev.open('w')
     179          dsp.close()
     180          self.assertRaises(ValueError, dsp.fileno)
     181          self.assertRaises(ValueError, dsp.read, 1)
     182          self.assertRaises(ValueError, dsp.write, b'x')
     183          self.assertRaises(ValueError, dsp.writeall, b'x')
     184          self.assertRaises(ValueError, dsp.bufsize)
     185          self.assertRaises(ValueError, dsp.obufcount)
     186          self.assertRaises(ValueError, dsp.obufcount)
     187          self.assertRaises(ValueError, dsp.obuffree)
     188          self.assertRaises(ValueError, dsp.getptr)
     189  
     190          mixer = ossaudiodev.openmixer()
     191          mixer.close()
     192          self.assertRaises(ValueError, mixer.fileno)
     193  
     194  def setUpModule():
     195      try:
     196          dsp = ossaudiodev.open('w')
     197      except (ossaudiodev.error, OSError) as msg:
     198          if msg.args[0] in (errno.EACCES, errno.ENOENT,
     199                             errno.ENODEV, errno.EBUSY):
     200              raise unittest.SkipTest(msg)
     201          raise
     202      dsp.close()
     203  
     204  if __name__ == "__main__":
     205      unittest.main()