test_ossaudiodev.py 4.76 KB
Newer Older
1 2 3
from test import test_support
test_support.requires('audio')

4 5 6 7 8 9 10 11 12 13 14 15
from test.test_support import verbose, findfile, TestFailed, TestSkipped

import errno
import fcntl
import ossaudiodev
import os
import sys
import select
import sunaudio
import time
import audioop

16 17 18 19 20 21 22 23 24 25 26
# Arggh, AFMT_S16_NE not defined on all platforms -- seems to be a
# fairly recent addition to OSS.
try:
    from ossaudiodev import AFMT_S16_NE
except ImportError:
    if sys.byteorder == "little":
        AFMT_S16_NE = ossaudiodev.AFMT_S16_LE
    else:
        AFMT_S16_NE = ossaudiodev.AFMT_S16_BE


27 28
SND_FORMAT_MULAW_8 = 1

29
def read_sound_file(path):
30
    fp = open(path, 'rb')
31 32 33 34 35 36 37 38
    size, enc, rate, nchannels, extra = sunaudio.gethdr(fp)
    data = fp.read()
    fp.close()

    if enc != SND_FORMAT_MULAW_8:
        print "Expect .au file with 8-bit mu-law samples"
        return

39 40 41 42 43 44
    # Convert the data to 16-bit signed.
    data = audioop.ulaw2lin(data, 2)
    return (data, rate, 16, nchannels)


def play_sound_file(data, rate, ssize, nchannels):
45
    try:
46
        dsp = ossaudiodev.open('w')
47
    except IOError, msg:
48 49 50 51 52
        if msg[0] in (errno.EACCES, errno.ENODEV, errno.EBUSY):
            raise TestSkipped, msg
        raise TestFailed, msg

    # at least check that these methods can be invoked
53 54 55 56 57
    dsp.bufsize()
    dsp.obufcount()
    dsp.obuffree()
    dsp.getptr()
    dsp.fileno()
58

59 60 61 62 63 64 65 66 67 68 69 70 71
    # Make sure the read-only attributes work.
    assert dsp.closed is False, "dsp.closed is not False"
    assert dsp.name == "/dev/dsp"
    assert dsp.mode == 'w', "bad dsp.mode: %r" % dsp.mode

    # And make sure they're really read-only.
    for attr in ('closed', 'name', 'mode'):
        try:
            setattr(dsp, attr, 42)
            raise RuntimeError("dsp.%s not read-only" % attr)
        except TypeError:
            pass

72
    # set parameters based on .au file headers
73
    dsp.setparameters(AFMT_S16_NE, nchannels, rate)
74 75
    t1 = time.time()
    print "playing test sound file..."
76 77
    dsp.write(data)
    dsp.close()
78 79
    t2 = time.time()
    print "elapsed time: %.1f sec" % (t2-t1)
80

81
def test_setparameters(dsp):
82 83 84 85 86 87 88
    # Two configurations for testing:
    #   config1 (8-bit, mono, 8 kHz) should work on even the most
    #      ancient and crufty sound card, but maybe not on special-
    #      purpose high-end hardware
    #   config2 (16-bit, stereo, 44.1kHz) should work on all but the
    #      most ancient and crufty hardware
    config1 = (ossaudiodev.AFMT_U8, 1, 8000)
89
    config2 = (AFMT_S16_NE, 2, 44100)
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

    for config in [config1, config2]:
        (fmt, channels, rate) = config
        if (dsp.setfmt(fmt) == fmt and
            dsp.channels(channels) == channels and
            dsp.speed(rate) == rate):
            break
    else:
        raise RuntimeError("unable to set audio sampling parameters: "
                           "you must have really weird audio hardware")

    # setparameters() should be able to set this configuration in
    # either strict or non-strict mode.
    result = dsp.setparameters(fmt, channels, rate, False)
    assert result == (fmt, channels, rate), \
           "setparameters%r: returned %r" % (config + result)
    result = dsp.setparameters(fmt, channels, rate, True)
    assert result == (fmt, channels, rate), \
           "setparameters%r: returned %r" % (config + result)

110 111
def test_bad_setparameters(dsp):

112 113 114 115 116
    # Now try some configurations that are presumably bogus: eg. 300
    # channels currently exceeds even Hollywood's ambitions, and
    # negative sampling rate is utter nonsense.  setparameters() should
    # accept these in non-strict mode, returning something other than
    # was requested, but should barf in strict mode.
117 118 119
    fmt = AFMT_S16_NE
    rate = 44100
    channels = 2
120 121 122 123 124 125 126 127 128 129 130 131 132 133
    for config in [(fmt, 300, rate),       # ridiculous nchannels
                   (fmt, -5, rate),        # impossible nchannels
                   (fmt, channels, -50),   # impossible rate
                  ]:
        (fmt, channels, rate) = config
        result = dsp.setparameters(fmt, channels, rate, False)
        assert result != config, \
               "setparameters: unexpectedly got requested configuration"

        try:
            result = dsp.setparameters(fmt, channels, rate, True)
            raise AssertionError("setparameters: expected OSSAudioError")
        except ossaudiodev.OSSAudioError, err:
            print "setparameters: got OSSAudioError as expected"
134 135

def test():
136 137
    (data, rate, ssize, nchannels) = read_sound_file(findfile('audiotest.au'))
    play_sound_file(data, rate, ssize, nchannels)
138 139 140 141 142 143 144 145 146 147 148

    dsp = ossaudiodev.open("w")
    try:
        test_setparameters(dsp)

        # Disabled because it fails under Linux 2.6 with ALSA's OSS
        # emulation layer.
        #test_bad_setparameters(dsp)
    finally:
        dsp.close()
        assert dsp.closed is True, "dsp.closed is not True"
149 150

test()