未翻訳のページ
このページはまだ日本語に翻訳されていないため、英語の原文を表示しています。 翻訳に協力する
ossaudiodev Module Complexity¶
The ossaudiodev module drives OSS (Open Sound System) audio devices: an audio device such as
/dev/dsp for playback and recording, and a mixer device such as /dev/mixer for volume
control. Data moves straight between your bytes and the device's file descriptor, so the only
calls whose cost grows are read(), write() and writeall(); every other call is a fixed
number of system calls.
Removed in Python 3.13
Deprecated in Python 3.11 and removed in Python 3.13 by PEP 594, with no standard-library replacement. The page covers the module as it is on Python 3.11 and 3.12 on Linux and FreeBSD; the examples also need an OSS audio device and mixer.
n is the bytes passed to write() or writeall(), or the size asked of read(). The bounds
price the module's own work. Waiting for the device - to accept data, to capture it, or to play
out its buffer - takes real time proportional to the audio involved, and is outside every bound;
the Notes say where a call waits. Every function and method takes its arguments by position only.
bufsize(), obufcount() and obuffree() count samples per channel, not bytes: multiply by the
sample width times the channel count to get bytes.
Complexity Reference¶
Functions¶
| Operation | Time | Space | Notes |
|---|---|---|---|
ossaudiodev.open(mode), ossaudiodev.open(device, mode) |
O(1) | O(1) | mode is 'r', 'w' or 'rw'; without device, the AUDIODEV environment variable, else /dev/dsp. A file that is not an audio device raises OSError here |
ossaudiodev.openmixer(), ossaudiodev.openmixer(device) |
O(1) | O(1) | Without device, the MIXERDEV environment variable, else /dev/mixer. A file that is not a mixer still opens, and fails at the first control call |
oss_audio_device¶
| Operation | Time | Space | Notes |
|---|---|---|---|
oss_audio_device.read(size) |
O(n) | O(n) | Allocates size bytes before reading; in blocking mode, waits until all of them are captured |
oss_audio_device.write(data) |
O(n) | O(1) | Writes from the caller's buffer and returns the bytes written: all of them in blocking mode, possibly fewer after nonblock() |
oss_audio_device.writeall(data) |
O(n) | O(1) | Waits for the device and writes until all of data is gone; returns None. In blocking mode it has the same effect as write() |
oss_audio_device.setfmt(format), oss_audio_device.channels(nchannels), oss_audio_device.speed(samplerate) |
O(1) | O(1) | Each returns the value the device actually set, which may differ from the request |
oss_audio_device.setparameters(format, nchannels, samplerate[, strict]) |
O(1) | O(1) | All three at once; returns (format, nchannels, samplerate) as set. With strict true, a value the device changed raises OSSAudioError |
oss_audio_device.getfmts() |
O(1) | O(1) | Bitmask of the supported AFMT_* formats |
oss_audio_device.bufsize(), oss_audio_device.obufcount(), oss_audio_device.obuffree() |
O(1) | O(1) | The whole output buffer, the part still to play, and the part free; in samples, not bytes |
oss_audio_device.nonblock() |
O(1) | O(1) | There is no way back to blocking mode |
oss_audio_device.sync() |
O(1) | O(1) | Waits until the buffer has played |
oss_audio_device.reset() |
O(1) | O(1) | Stops at once, discarding what is buffered |
oss_audio_device.post() |
O(1) | O(1) | Tells the driver a pause in output is likely |
oss_audio_device.fileno() |
O(1) | O(1) | |
oss_audio_device.close() |
O(1) | O(1) | Waits for buffered playback to finish, as sync() does. A second call does nothing; a with block calls it on exit. fileno() and every device call then raise ValueError |
oss_audio_device.closed, oss_audio_device.name, oss_audio_device.mode |
O(1) | O(1) | Read-only |
oss_mixer_device¶
| Operation | Time | Space | Notes |
|---|---|---|---|
oss_mixer_device.controls(), oss_mixer_device.stereocontrols(), oss_mixer_device.reccontrols() |
O(1) | O(1) | Bitmasks of the available, the stereo and the recordable controls; bit c is the control numbered c |
oss_mixer_device.get(control) |
O(1) | O(1) | Returns (left, right), each 0 to 100. A negative control number, or one above SOUND_MIXER_NRDEVICES, raises OSSAudioError |
oss_mixer_device.set(control, (left, right)) |
O(1) | O(1) | Returns the volume as set. A control number get() rejects, or a volume outside 0 to 100, raises OSSAudioError |
oss_mixer_device.get_recsrc(), oss_mixer_device.set_recsrc(bitmask) |
O(1) | O(1) | Bitmask of the controls recording now; set_recsrc() returns the new one |
oss_mixer_device.fileno() |
O(1) | O(1) | |
oss_mixer_device.close() |
O(1) | O(1) | A second call does nothing; a with block calls it on exit. fileno() and every device call then raise ValueError |
Constants and exceptions¶
| Operation | Time | Space | Notes |
|---|---|---|---|
ossaudiodev.OSSAudioError, ossaudiodev.error |
O(1) | O(1) | One class under two names, raised for a bad open() mode, a mixer control number or volume out of range, and a strict mismatch in setparameters(); failed system calls raise OSError |
ossaudiodev.control_labels, ossaudiodev.control_names |
O(1) | O(1) | Lists indexed by control number, one entry per control |
ossaudiodev.AFMT_*, ossaudiodev.SOUND_MIXER_*, ossaudiodev.SNDCTL_* |
O(1) | O(1) | Integer constants from the system's soundcard.h: sample formats, mixer control numbers, and raw ioctl requests |
Playing Audio¶
Configure the device, then write. writeall() costs the bytes it is given, plus however long the
device takes to accept them; sync() then waits until the buffer has played.
import ossaudiodev
with ossaudiodev.open("w") as dsp: # O(1)
# strict: raise rather than accept other values from the device
fmt, channels, rate = dsp.setparameters(ossaudiodev.AFMT_S16_LE, 2, 44100, True) # O(1)
frame = 2 * channels # bytes per sample: 16 bits for each channel
pcm = bytes(frame * rate // 10) # a tenth of a second of silence
dsp.writeall(pcm) # O(n), waits until all of it is written
dsp.sync() # O(1), waits until it has played
assert dsp.closed
Recording Audio¶
read(size) allocates size bytes before it asks the device for them, so the chunk size, not
the recording, sets the memory one call needs. Keeping every chunk is what makes memory grow with
the whole recording.
import ossaudiodev
with ossaudiodev.open("r") as dsp:
dsp.setparameters(ossaudiodev.AFMT_S16_LE, 1, 16000)
chunks = [dsp.read(4096) for _ in range(10)] # O(4096) each, waits for the samples
audio = b"".join(chunks) # linear in the bytes recorded
assert len(audio) == 10 * 4096
Writing Without Waiting¶
A write of no more than obuffree() worth of samples fits in the buffer, so it does not wait.
obuffree() counts samples, not bytes, so scale it before comparing it with a length.
import ossaudiodev
with ossaudiodev.open("w") as dsp:
fmt, channels, rate = dsp.setparameters(ossaudiodev.AFMT_S16_LE, 2, 44100, True)
frame = 2 * channels # bytes per sample: 16 bits for each channel
chunk = bytes(frame * 1024) # 1,024 samples of silence
room = dsp.obuffree() * frame # O(1) - samples times bytes per sample
if room >= len(chunk):
assert dsp.write(chunk) == len(chunk) # O(n), fits in the buffer
Mixer Volumes¶
get() and set() check the control number, and set() the volume, before they ask the
device, and raise OSSAudioError for one out of range.
import ossaudiodev
with ossaudiodev.openmixer() as mixer: # O(1)
pcm = ossaudiodev.SOUND_MIXER_PCM
assert ossaudiodev.control_names[pcm] == 'pcm'
if mixer.controls() & (1 << pcm): # O(1) - one bit per control
left, right = mixer.set(pcm, (80, 80)) # O(1)
assert 0 <= left <= 100 and 0 <= right <= 100
try:
mixer.set(pcm, (101, 0))
except ossaudiodev.OSSAudioError as error:
assert 'between 0 and 100' in str(error)
else:
raise AssertionError('a volume over 100 was accepted')
Performance Best Practices¶
✅ Do:
- Read in fixed-size chunks; each
read(size)holdssizebytes, whatever the recording's length - Scale
obuffree(),obufcount()andbufsize()by the bytes per sample before comparing them with a byte count - Check what
setparameters()returns, or passTrueas its fourth argument,strict; the device may choose other values
❌ Avoid:
nonblock()unless you mean it - it cannot be undone, andwrite()may then write less than it was given- Calling
sync()where latency matters - it waits for the whole buffer to play - Assuming
openmixer()succeeding means a mixer is there - the first control call is the check
Version Notes¶
- Python 3.11+:
import ossaudiodevemits aDeprecationWarning - Python 3.13+: The module is removed;
import ossaudiodevraisesModuleNotFoundError